diff --git a/Core/manifest.mf b/Core/manifest.mf index cc13c3055d..fef8f5793b 100644 --- a/Core/manifest.mf +++ b/Core/manifest.mf @@ -2,7 +2,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.core/10 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml -OpenIDE-Module-Implementation-Version: 15 +OpenIDE-Module-Implementation-Version: 16 OpenIDE-Module-Requires: org.openide.windows.WindowManager AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index add7b7b717..f52a185822 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -21,5 +21,5 @@ nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true source.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip!/Source/ -spec.version.base=10.4 +spec.version.base=10.5 diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index a2ddc46460..3f1e5f172d 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -177,7 +177,7 @@ 3 - 1.0 + 1.1 diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 5f69fc8a7f..eb4dbbab6b 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,6 +40,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class GetTagNameAndCommentDialog extends JDialog { + private static final long serialVersionUID = 1L; private static final String NO_TAG_NAMES_MESSAGE = NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.noTags"); private final HashMap tagNames = new HashMap<>(); @@ -47,8 +48,8 @@ public class GetTagNameAndCommentDialog extends JDialog { public static class TagNameAndComment { - private TagName tagName; - private String comment; + private final TagName tagName; + private final String comment; private TagNameAndComment(TagName tagName, String comment) { this.tagName = tagName; @@ -67,8 +68,7 @@ public class GetTagNameAndCommentDialog extends JDialog { /** * Show the Tag Name and Comment Dialog and return the TagNameAndContent * chosen by the user. The dialog will be centered with the main autopsy - * window as its owner. To set another window as the owner use {@link #doDialog(java.awt.Window) - * } + * window as its owner. * * @return a TagNameAndComment instance containing the TagName selected by * the user and the entered comment, or null if the user canceled diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 6e1d353e22..6291ff7521 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -35,6 +35,7 @@ import org.openide.util.HelpCtx; import org.sleuthkit.datamodel.Content; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -271,7 +272,10 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -714,16 +714,14 @@ public class Case implements SleuthkitCase.ErrorObserver { } /** - * Adds the image to the current case after it has been added to the DB. + * Adds an image to the current case after it has been added to the DB. * Sends out event and reopens windows if needed. * - * @param imgPaths the paths of the image that being added - * @param imgId the ID of the image that being added - * @param timeZone the timeZone of the image where it's added + * @param imgPath The path of the image file. + * @param imgId The ID of the image. + * @param timeZone The time zone of the image. * - * @deprecated As of release 4.0, replaced by {@link #notifyAddingDataSource(java.util.UUID) and - * {@link #notifyDataSourceAdded(org.sleuthkit.datamodel.Content, java.util.UUID) and - * {@link #notifyFailedAddingDataSource(java.util.UUID)} + * @deprecated As of release 4.0 */ @Deprecated public Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index c699eb740d..977c7ef6b0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -190,9 +190,9 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { * Sets the configuration of the data source processor without using the * configuration panel. * - * @param imagePath Path to the image file. + * @param drivePath Path to the local drive. * @param timeZone The time zone to use when processing dates - * and times for the image, obtained from + * and times for the local drive, obtained from * java.util.TimeZone.getID. * @param ignoreFatOrphanFiles Whether to parse orphans if the image has a * FAT filesystem. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java index 4eae9e4e7e..c7825b6458 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java @@ -43,7 +43,6 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { * TODO: Remove the setDataSourceOptionsCalled flag and the settings fields * when the deprecated method setDataSourceOptions is removed. */ - private String deviceId; private List localFilePaths; private boolean setDataSourceOptionsCalled; @@ -123,10 +122,9 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { @Override public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { if (!setDataSourceOptionsCalled) { - deviceId = UUID.randomUUID().toString(); localFilePaths = Arrays.asList(configPanel.getContentPaths().split(LocalFilesPanel.FILES_SEP)); } - run(deviceId, "", localFilePaths, progressMonitor, callback); + run(UUID.randomUUID().toString(), configPanel.getFileSetName(), localFilePaths, progressMonitor, callback); } /** @@ -162,7 +160,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { * is a "best effort" cancellation, with no guarantees that the case * database will be unchanged. If cancellation succeeded, the list of new * data sources returned by the background task will be empty. - * + * * TODO (AUT-1907): Implement cancellation by deleting rows added to the * case database. */ @@ -194,7 +192,8 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { */ @Deprecated public void setDataSourceOptions(String paths) { - this.localFilePaths = Arrays.asList(configPanel.getContentPaths().split(LocalFilesPanel.FILES_SEP)); + //LocalFilesPanel.FILES_SEP is currently "," + this.localFilePaths = Arrays.asList(paths.split(LocalFilesPanel.FILES_SEP)); setDataSourceOptionsCalled = true; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.form index eb9d6182bb..4a502d97bf 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.form @@ -47,21 +47,30 @@ - - - - - + + + + + + + - + - - + + + + + + + + + @@ -70,17 +79,23 @@ - - - + + - + + - + + + + + + + @@ -151,5 +166,22 @@ + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java index eae470e0b4..99ba5ec231 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.casemodule; +import java.awt.Dialog; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; @@ -32,6 +33,10 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import java.util.logging.Level; +import javax.swing.JOptionPane; +import org.openide.DialogDescriptor; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PathValidator; @@ -47,6 +52,7 @@ class LocalFilesPanel extends JPanel { private static LocalFilesPanel instance; public static final String FILES_SEP = ","; private static final Logger logger = Logger.getLogger(LocalFilesPanel.class.getName()); + private String displayName = ""; /** * Creates new form LocalFilesPanel @@ -67,6 +73,7 @@ class LocalFilesPanel extends JPanel { localFileChooser.setMultiSelectionEnabled(true); errorLabel.setVisible(false); selectedPaths.setText(""); + this.displayNameLabel.setText(NbBundle.getMessage(this.getClass(), "LocalFilesPanel.displayNameLabel.text")); } //@Override @@ -137,6 +144,8 @@ class LocalFilesPanel extends JPanel { selectedPaths.setText(""); enableNext = false; errorLabel.setVisible(false); + displayName = ""; + this.displayNameLabel.setText(NbBundle.getMessage(this.getClass(), "LocalFilesPanel.displayNameLabel.text")); } @Override @@ -157,6 +166,10 @@ class LocalFilesPanel extends JPanel { pcs.removePropertyChangeListener(pcl); } + public String getFileSetName() { + return this.displayName; + } + @Override public String toString() { return NbBundle.getMessage(this.getClass(), "LocalFilesDSProcessor.toString.text"); @@ -180,6 +193,8 @@ class LocalFilesPanel extends JPanel { jScrollPane2 = new javax.swing.JScrollPane(); selectedPaths = new javax.swing.JTextArea(); errorLabel = new javax.swing.JLabel(); + jButton1 = new javax.swing.JButton(); + displayNameLabel = new javax.swing.JLabel(); localFileChooser.setApproveButtonText(org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.localFileChooser.approveButtonText")); // NOI18N localFileChooser.setApproveButtonToolTipText(org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.localFileChooser.approveButtonToolTipText")); // NOI18N @@ -218,37 +233,57 @@ class LocalFilesPanel extends JPanel { errorLabel.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.errorLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.jButton1.text")); // NOI18N + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(displayNameLabel, org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.displayNameLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(infoLabel) - .addGap(0, 0, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 353, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(infoLabel) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 389, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(selectButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(clearButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(clearButton, javax.swing.GroupLayout.DEFAULT_SIZE, 69, Short.MAX_VALUE)) .addGap(2, 2, 2)) .addGroup(layout.createSequentialGroup() - .addComponent(errorLabel) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(errorLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(displayNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jButton1))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(infoLabel) - .addGap(5, 5, 5) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addComponent(selectButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(clearButton))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(errorLabel)) + .addGap(36, 36, 36) + .addComponent(clearButton)) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(displayNameLabel)) + .addGap(13, 13, 13) + .addComponent(errorLabel) + .addGap(7, 7, 7)) ); }// //GEN-END:initComponents @@ -291,10 +326,20 @@ class LocalFilesPanel extends JPanel { }//GEN-LAST:event_clearButtonActionPerformed + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + String displayName = JOptionPane.showInputDialog("New Display Name: "); + if (displayName != null && !displayName.equals("")) { + this.displayName = displayName; + this.displayNameLabel.setText("Display Name: " + this.displayName); + } + }//GEN-LAST:event_jButton1ActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton clearButton; + private javax.swing.JLabel displayNameLabel; private javax.swing.JLabel errorLabel; private javax.swing.JLabel infoLabel; + private javax.swing.JButton jButton1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JTextArea jTextArea1; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/OpenRecentCasePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/OpenRecentCasePanel.java index 07706cc798..f7035effbb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/OpenRecentCasePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/OpenRecentCasePanel.java @@ -156,9 +156,6 @@ class OpenRecentCasePanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - /** - * @inheritDoc - */ @Override public int getRowCount() { int count = 0; @@ -170,17 +167,11 @@ class OpenRecentCasePanel extends javax.swing.JPanel { return count; } - /** - * @inheritDoc - */ @Override public int getColumnCount() { return 2; } - /** - * @inheritDoc - */ @Override public String getColumnName(int column) { String colName = null; @@ -197,9 +188,6 @@ class OpenRecentCasePanel extends javax.swing.JPanel { return colName; } - /** - * @inheritDoc - */ @Override public Object getValueAt(int rowIndex, int columnIndex) { Object ret = null; @@ -217,17 +205,11 @@ class OpenRecentCasePanel extends javax.swing.JPanel { return ret; } - /** - * @inheritDoc - */ @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } - /** - * @inheritDoc - */ @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index 4d540fa5cb..5b958cd5a7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -512,6 +512,7 @@ public class FileManager implements Closeable { * Helper (internal) method to recursively add contents of a folder. Node * passed in can be a file or directory. Children of directories are added. * + * @param trans A case database transaction. * @param parentVd Dir that is the parent of localFile * @param localFile File/Dir that we are adding * @param addProgressUpdater notifier to receive progress notifications on @@ -569,6 +570,7 @@ public class FileManager implements Closeable { * @param parentFile parent file object container (such as virtual * directory, another local file, or fscontent File), * @param localFile File that we are adding + * @param trans A case database transaction. * * @return newly created local file object added to the database * diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index 512cf6393c..917eaf404b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2013 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -385,7 +385,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont /** * Sets the DataView (The tabbed panel) by offset * - * @param page Page to display (1-based counting) + * @param offset Page to display (1-based counting) */ private void setDataViewByOffset(long offset) { if (this.dataSource == null) { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 9c1efe9b21..b8e03d51d6 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -22,8 +22,6 @@ import java.awt.CardLayout; import java.awt.Component; import java.awt.Dimension; import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.logging.Level; import org.openide.nodes.Node; import org.openide.util.NbBundle; @@ -47,7 +45,6 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo //UI private final MediaViewVideoPanel videoPanel; private final boolean videoPanelInited; - private final SortedSet videoExtensions; // get them from the panel private final MediaViewImagePanel imagePanel; private final boolean imagePanelInited; @@ -64,7 +61,6 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo // get the right panel for our platform videoPanel = MediaViewVideoPanel.createVideoPanel(); videoPanelInited = videoPanel.isInited(); - videoExtensions = new TreeSet<>(videoPanel.getExtensionsList()); imagePanel = new MediaViewImagePanel(); imagePanelInited = imagePanel.isInited(); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/GstVideoPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/GstVideoPanel.java index 9c3036db6c..8f69f82386 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/GstVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/GstVideoPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.corecomponents; +import com.google.common.io.Files; import java.awt.Dimension; import java.awt.Image; import java.awt.image.BufferedImage; @@ -680,6 +681,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progress.buffering")); progress.start(100); try { + Files.createParentDirs(tempFile); return ContentUtils.writeToFile(sourceFile, tempFile, progress, this, true); } catch (IOException ex) { logger.log(Level.WARNING, "Error buffering file", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java index a3dc773abb..b9ad634ff5 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java @@ -28,7 +28,9 @@ import java.util.TreeSet; import java.util.logging.Level; import javax.swing.JPanel; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; /** * Video viewer part of the Media View layered pane. Uses different engines @@ -131,18 +133,38 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture @Override public boolean isSupported(AbstractFile file) { - /* - * TODO (AUT-2042): Is this the logic we want? - */ String extension = file.getNameExtension(); + /** + * Although it seems too restrictive, requiring both a supported + * extension and a supported MIME type prevents two undesirable + * behaviors: + * + * 1) Until AUT-1766 and AUT-1801 are fixed, we incorrectly identify all + * iff files as audio/aiff. This means that if this panel went with the + * looser 'mime type OR extension' criteria we use for images, then this + * panel would attempt (and fail) to display all iff files, even non + * audio ones. + * + * 2) The looser criteria means we are less confident about the files we + * are potentialy sending to GStreamer on 32bit jvms. We are less + * comfortable with the error handling for GStreamer, and don't want to + * send it files which might cause it trouble. + */ if (AUDIO_EXTENSIONS.contains("." + extension) || getExtensionsList().contains("." + extension)) { SortedSet mimeTypes = new TreeSet<>(getMimeTypes()); - String mimeType = file.getMIMEType(); - if (nonNull(mimeType)) { - return mimeTypes.contains(mimeType); - } else { - return getExtensionsList().contains("." + extension); + try { + String mimeType = new FileTypeDetector().detect(file); + if (nonNull(mimeType)) { + return mimeTypes.contains(mimeType); + } + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); + if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) { + return true; + } } + + return getExtensionsList().contains("." + extension); } return false; } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.java index 8b4af64dc3..6ebaa4293f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.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 2013-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.corecomponents; @@ -467,7 +480,8 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { /** * Enables/disables the multi-user settings, based upon input provided * - * @param enabled true means enable, false means disable + * @param textFields The text fields to enable/disable. + * @param enabled True means enable, false means disable. */ private static void enableMultiUserComponents(Collection textFields, boolean enabled) { for (JTextField textField : textFields) { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java index e7a39f62ce..bb16323625 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java @@ -132,7 +132,7 @@ class ThumbnailViewChildren extends Children.Keys { return new Node[]{pageNode}; } - public static boolean isSupported(Node node) { + static boolean isSupported(Node node) { if (node != null) { Content content = node.getLookup().lookup(Content.class); if (content != null) { 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/ExecUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java index b0a04d0d56..0507e55cd6 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -96,9 +96,6 @@ public final class ExecUtil { this.startTimeInSeconds = (new Date().getTime()) / 1000; } - /** - * @inheritDoc - */ @Override public boolean shouldTerminateProcess() { long currentTimeInSeconds = (new Date().getTime()) / 1000; @@ -120,9 +117,6 @@ public final class ExecUtil { */ public static int execute(ProcessBuilder processBuilder) throws SecurityException, IOException { return ExecUtil.execute(processBuilder, 30, TimeUnit.DAYS, new ProcessTerminator() { - /** - * @inheritDoc - */ @Override public boolean shouldTerminateProcess() { return false; diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index f6e87d22e5..f4f1e99ab3 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -32,10 +32,10 @@ import java.io.InputStream; import java.nio.file.Paths; import java.text.MessageFormat; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Objects; import static java.util.Objects.nonNull; import java.util.SortedSet; import java.util.TreeSet; @@ -78,7 +78,7 @@ public class ImageUtils { /** * save thumbnails to disk as this format */ - private static final String FORMAT = "png"; //NON-NLS //NOI18N + private static final String FORMAT = "png"; //NON-NLS public static final int ICON_SIZE_SMALL = 50; public static final int ICON_SIZE_MEDIUM = 100; @@ -86,12 +86,11 @@ public class ImageUtils { private static final BufferedImage DEFAULT_THUMBNAIL; - private static final String IMAGE_GIF_MIME = "image/gif"; //NOI18N NON-NLS - private static final SortedSet GIF_MIME_SET = ImmutableSortedSet.copyOf(new String[]{IMAGE_GIF_MIME}); + private static final List GIF_EXTENSION_LIST = Arrays.asList("gif"); + private static final SortedSet GIF_MIME_SET = ImmutableSortedSet.copyOf(new String[]{"image/gif"}); private static final List SUPPORTED_IMAGE_EXTENSIONS; private static final SortedSet SUPPORTED_IMAGE_MIME_TYPES; - private static final List CONDITIONAL_MIME_TYPES = Arrays.asList("audio/x-aiff", "application/octet-stream"); //NOI18N NON-NLS private static final boolean openCVLoaded; @@ -99,9 +98,9 @@ public class ImageUtils { ImageIO.scanForPlugins(); BufferedImage tempImage; try { - tempImage = ImageIO.read(ImageUtils.class.getResourceAsStream("/org/sleuthkit/autopsy/images/file-icon.png"));//NON-NLS //NOI18N + tempImage = ImageIO.read(ImageUtils.class.getResourceAsStream("/org/sleuthkit/autopsy/images/file-icon.png"));//NON-NLS } catch (IOException ex) { - LOGGER.log(Level.SEVERE, "Failed to load default icon.", ex); //NOI18N NON-NLS + LOGGER.log(Level.SEVERE, "Failed to load default icon.", ex); //NON-NLS tempImage = null; } DEFAULT_THUMBNAIL = tempImage; @@ -110,23 +109,22 @@ public class ImageUtils { boolean openCVLoadedTemp; try { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); - if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { //NOI18N NON-NLS - System.loadLibrary("opencv_ffmpeg248_64"); //NOI18N NON-NLS + if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { //NON-NLS + System.loadLibrary("opencv_ffmpeg248_64"); //NON-NLS } else { - System.loadLibrary("opencv_ffmpeg248"); //NOI18N NON-NLS + System.loadLibrary("opencv_ffmpeg248"); //NON-NLS } openCVLoadedTemp = true; } catch (UnsatisfiedLinkError e) { openCVLoadedTemp = false; - LOGGER.log(Level.SEVERE, "OpenCV Native code library failed to load", e); //NOI18N NON-NLS + LOGGER.log(Level.SEVERE, "OpenCV Native code library failed to load", e); //NON-NLS //TODO: show warning bubble } openCVLoaded = openCVLoadedTemp; SUPPORTED_IMAGE_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); - SUPPORTED_IMAGE_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); /* * special cases and variants that we support, but don't get registered @@ -137,8 +135,8 @@ public class ImageUtils { "image/x-ms-bmp", //NON-NLS "image/x-portable-graymap", //NON-NLS "image/x-portable-bitmap", //NON-NLS - "application/x-123")); //TODO: is this correct? -jm //NOI18N NON-NLS - SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); //NOI18N NON-NLS + "application/x-123")); //TODO: is this correct? -jm //NON-NLS + SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); //NON-NLS } /** @@ -151,7 +149,7 @@ public class ImageUtils { */ private static final Executor imageSaver = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder() - .namingPattern("icon saver-%d").build()); //NOI18N NON-NLS + .namingPattern("thumbnail-saver-%d").build()); //NON-NLS public static List getSupportedImageExtensions() { return Collections.unmodifiableList(SUPPORTED_IMAGE_EXTENSIONS); @@ -163,20 +161,7 @@ public class ImageUtils { /** * Get the default thumbnail, which is the icon for a file. Used when we can - * not generate content based thumbnail. - * - * @return - * - * @deprecated use {@link #getDefaultThumbnail() } instead. - */ - @Deprecated - public static Image getDefaultIcon() { - return getDefaultThumbnail(); - } - - /** - * Get the default thumbnail, which is the icon for a file. Used when we can - * not generate content based thumbnail. + * not generate a content based thumbnail. * * @return the default thumbnail */ @@ -196,9 +181,6 @@ public class ImageUtils { */ public static boolean thumbnailSupported(Content content) { - if (content.getSize() == 0) { - return false; - } if (!(content instanceof AbstractFile)) { return false; } @@ -206,79 +188,84 @@ public class ImageUtils { return VideoUtils.isVideoThumbnailSupported(file) || isImageThumbnailSupported(file); - } /** - * is the file an image that we can read and generate a thumbnail for + * Is the file an image that we can read and generate a thumbnail for? * - * @param file + * @param file the AbstractFile to test * * @return true if the file is an image we can read and generate thumbnail * for. */ public static boolean isImageThumbnailSupported(AbstractFile file) { - return isMediaThumbnailSupported(file, SUPPORTED_IMAGE_MIME_TYPES, SUPPORTED_IMAGE_EXTENSIONS, CONDITIONAL_MIME_TYPES) - || hasImageFileHeader(file); + return isMediaThumbnailSupported(file, "image/", SUPPORTED_IMAGE_MIME_TYPES, SUPPORTED_IMAGE_EXTENSIONS) || hasImageFileHeader(file);//NON-NLS } /** - * Checks the MIME type of a file to determine whether it is a GIF. If the - * MIME type is not known, checks for a "gif" extension. + * Checks the MIME type and/or extension of a file to determine whether it + * is a GIF. * - * @param file The file to be checked. + * @param file the AbstractFile to test * - * @return True or false + * @return true if the file is a gif */ public static boolean isGIF(AbstractFile file) { - String mimeType = file.getMIMEType(); - if (nonNull(mimeType)) { - return IMAGE_GIF_MIME.equalsIgnoreCase(mimeType); - } else { - return "gif".equalsIgnoreCase(file.getNameExtension()); //NOI18N - } + return isMediaThumbnailSupported(file, null, GIF_MIME_SET, GIF_EXTENSION_LIST); } /** - * Check if a file is "supported" by checking its mimetype and extension + * Check if making a thumbnail for the given file is supported by checking + * its extension and/or MIME type against the supplied collections. * * //TODO: this should move to a better place. Should ImageUtils and * VideoUtils both implement/extend some base interface/abstract class. That * would be the natural place to put this. * - * @param file - * @param supportedMimeTypes a set of mimetypes that the could have to be - * supported - * @param supportedExtension a set of extensions a file could have to be - * supported if the mime lookup fails or is - * inconclusive - * @param conditionalMimes a set of mimetypes that a file could have to be - * supoprted if it also has a supported extension + * @param file the AbstractFile to test + * @param mimeTypePrefix a MIME 'top-level type name' such as "image/", + * including the "/". In addition to the list of + * supported MIME types, any type that starts with + * this prefix will be regarded as supported + * @param supportedMimeTypes a collection of mimetypes that are supported + * @param supportedExtension a collection of extensions that are supported * * @return true if a thumbnail can be generated for the given file based on - * the given lists of supported mimetype and extensions + * the given MIME type prefix and lists of supported MIME types and + * extensions */ - static boolean isMediaThumbnailSupported(AbstractFile file, final SortedSet supportedMimeTypes, final List supportedExtension, List conditionalMimes) { - if (file.getSize() == 0) { + static boolean isMediaThumbnailSupported(AbstractFile file, String mimeTypePrefix, final Collection supportedMimeTypes, final List supportedExtension) { + if (false == file.isFile() || file.getSize() <= 0) { return false; } - String mimeType = file.getMIMEType(); + String extension = file.getNameExtension(); - if (nonNull(mimeType)) { - return supportedMimeTypes.contains(mimeType) - || (conditionalMimes.contains(mimeType.toLowerCase()) - && supportedExtension.contains(extension)); + + if (StringUtils.isNotBlank(extension) && supportedExtension.contains(extension)) { + return true; } else { - return StringUtils.isNotBlank(extension) && supportedExtension.contains(extension); + try { + String mimeType = getFileTypeDetector().detect(file); + if (StringUtils.isNotBlank(mimeTypePrefix) && mimeType.startsWith(mimeTypePrefix)) { + return true; + } + return supportedMimeTypes.contains(mimeType); + } catch (FileTypeDetectorInitException | TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error determining MIME type of " + getContentPathSafe(file), ex);//NON-NLS + return false; + } } } /** - * returns a lazily instatiated FileTypeDetector + * //TODO: AUT-2057 this FileTypeDetector needs to be recreated when the + * user adds new user defined file types. + * + * get a FileTypeDetector * * @return a FileTypeDetector * - * @throws FileTypeDetectorInitException if a initializing the + * @throws FileTypeDetectorInitException if initializing the * FileTypeDetector failed. */ synchronized private static FileTypeDetector getFileTypeDetector() throws FileTypeDetector.FileTypeDetectorInitException { @@ -292,27 +279,8 @@ public class ImageUtils { * Get a thumbnail of a specified size for the given image. Generates the * thumbnail if it is not already cached. * - * @param content - * @param iconSize - * - * @return a thumbnail for the given image or a default one if there was a - * problem making a thumbnail. - * - * @deprecated use {@link #getThumbnail(org.sleuthkit.datamodel.Content, int) - * } instead. - */ - @Nonnull - @Deprecated - public static BufferedImage getIcon(Content content, int iconSize) { - return getThumbnail(content, iconSize); - } - - /** - * Get a thumbnail of a specified size for the given image. Generates the - * thumbnail if it is not already cached. - * - * @param content - * @param iconSize + * @param content the content to generate a thumbnail for + * @param iconSize the size (one side of a square) in pixels to generate * * @return a thumbnail for the given image or a default one if there was a * problem making a thumbnail. @@ -334,34 +302,13 @@ public class ImageUtils { } } - /** - * Get a thumbnail of a specified size for the given image. Generates the - * thumbnail if it is not already cached. - * - * @param content - * @param iconSize - * - * @return File object for cached image. Is guaranteed to exist, as long as - * there was not an error generating or saving the thumbnail. - * - * @deprecated use {@link #getCachedThumbnailFile(org.sleuthkit.datamodel.Content, int) - * } instead. - * - */ - @Nullable - @Deprecated - public static File getIconFile(Content content, int iconSize) { - return getCachedThumbnailFile(content, iconSize); - - } - /** * * Get a thumbnail of a specified size for the given image. Generates the * thumbnail if it is not already cached. * - * @param content - * @param iconSize + * @param content the content to generate a thumbnail for + * @param iconSize the size (one side of a square) in pixels to generate * * @return File object for cached image. Is guaranteed to exist, as long as * there was not an error generating or saving the thumbnail. @@ -373,26 +320,10 @@ public class ImageUtils { } /** - * Get a file object for where the cached icon should exist. The returned - * file may not exist. + * Get the location of the cached thumbnail for a file with the given fileID + * as a java {@link File}. The returned File may not exist on disk yet. * - * @param id - * - * @return - * - * @deprecated use {@link #getCachedThumbnailLocation(long) } instead - */ - @Deprecated - - public static File getFile(long id) { - return getCachedThumbnailLocation(id); - } - - /** - * Get a file object for where the cached thumbnail should exist. The - * returned file may not exist. - * - * @param fileID + * @param fileID the fileID to get the cached thumbnail location for * * @return a File object representing the location of the cached thumbnail. * This file may not actually exist(yet). Returns null if there was @@ -401,19 +332,18 @@ public class ImageUtils { private static File getCachedThumbnailLocation(long fileID) { try { String cacheDirectory = Case.getCurrentCase().getCacheDirectory(); - return Paths.get(cacheDirectory, "thumbnails", fileID + ".png").toFile(); //NOI18N NON-NLS + return Paths.get(cacheDirectory, "thumbnails", fileID + ".png").toFile(); //NON-NLS } catch (IllegalStateException e) { LOGGER.log(Level.WARNING, "Could not get cached thumbnail location. No case is open."); //NON-NLS return null; } - } /** * Do a direct check to see if the given file has an image file header. * NOTE: Currently only jpeg and png are supported. * - * @param file + * @param file the AbstractFile to check * * @return true if the given file has one of the supported image headers. */ @@ -424,7 +354,7 @@ public class ImageUtils { /** * Check if the given file is a jpeg based on header. * - * @param file + * @param file the AbstractFile to check * * @return true if jpeg file, false otherwise */ @@ -449,7 +379,7 @@ public class ImageUtils { /** * Check if the given file is a png based on header. * - * @param file + * @param file the AbstractFile to check * * @return true if png file, false otherwise */ @@ -481,7 +411,7 @@ public class ImageUtils { if (bytesRead != buffLength) { //ignore if can't read the first few bytes, not an image - throw new TskCoreException("Could not read " + buffLength + " bytes from " + file.getName()); //NOI18N + throw new TskCoreException("Could not read " + buffLength + " bytes from " + file.getName());//NON-NLS } return fileHeaderBuffer; } @@ -498,7 +428,7 @@ public class ImageUtils { */ static public int getImageWidth(AbstractFile file) throws IOException { return getImageProperty(file, - "ImageIO could not determine width of {0}: ", //NOI18N NON-NLS + "ImageIO could not determine width of {0}: ", //NON-NLS imageReader -> imageReader.getWidth(0) ); } @@ -515,7 +445,7 @@ public class ImageUtils { */ static public int getImageHeight(AbstractFile file) throws IOException { return getImageProperty(file, - "ImageIO could not determine height of {0}: ", //NOI18N NON-NLS + "ImageIO could not determine height of {0}: ", //NON-NLS imageReader -> imageReader.getHeight(0) ); } @@ -537,7 +467,7 @@ public class ImageUtils { /** * Private template method designed to be used as the implementation of * public methods that pull particular (usually meta-)data out of a image - * file. ./** + * file. * * @param the type of the property to be retrieved. * @param file the file to extract the data from @@ -598,8 +528,9 @@ public class ImageUtils { * but is not started automatically. Clients are responsible for running the * task, monitoring its progress, and using its result. * - * @param file the file to create a thumbnail for - * @param iconSize the size of the thumbnail + * @param file The file to create a thumbnail for. + * @param iconSize The size of the thumbnail. + * @param defaultOnFailure Whether or not to default on failure. * * @return a new Task that returns a thumbnail as its result. */ @@ -612,7 +543,7 @@ public class ImageUtils { */ static private class GetThumbnailTask extends ReadImageTaskBase { - private static final String FAILED_TO_READ_IMAGE_FOR_THUMBNAIL_GENERATION = "Failed to read {0} for thumbnail generation."; //NOI18N NON-NLS + private static final String FAILED_TO_READ_IMAGE_FOR_THUMBNAIL_GENERATION = "Failed to read {0} for thumbnail generation."; //NON-NLS private final int iconSize; private final File cacheFile; @@ -646,7 +577,7 @@ public class ImageUtils { return SwingFXUtils.toFXImage(cachedThumbnail, null); } } catch (Exception ex) { - LOGGER.log(Level.WARNING, "ImageIO had a problem reading the cached thumbnail for {0}: " + ex.toString(), ImageUtils.getContentPathSafe(file)); //NOI18N NON-NLS + LOGGER.log(Level.WARNING, "ImageIO had a problem reading the cached thumbnail for {0}: " + ex.toString(), ImageUtils.getContentPathSafe(file)); //NON-NLS cacheFile.delete(); //since we can't read the file we might as well delete it. } } @@ -666,7 +597,7 @@ public class ImageUtils { if (defaultOnFailure) { thumbnail = DEFAULT_THUMBNAIL; } else { - throw new IIOException("Failed to generate a thumbnail for " + getContentPathSafe(file)); + throw new IIOException("Failed to generate a thumbnail for " + getContentPathSafe(file));//NON-NLS } } @@ -686,7 +617,7 @@ public class ImageUtils { thumbnail = ScalrWrapper.resizeFast(bufferedImage, iconSize); } catch (IllegalArgumentException | OutOfMemoryError e) { // if resizing does not work due to extreme aspect ratio or oom, crop the image instead. - LOGGER.log(Level.WARNING, "Cropping {0}, because it could not be scaled: " + e.toString(), ImageUtils.getContentPathSafe(file)); //NOI18N NON-NLS + LOGGER.log(Level.WARNING, "Cropping {0}, because it could not be scaled: " + e.toString(), ImageUtils.getContentPathSafe(file)); //NON-NLS final int height = bufferedImage.getHeight(); final int width = bufferedImage.getWidth(); @@ -696,11 +627,11 @@ public class ImageUtils { try { thumbnail = ScalrWrapper.cropImage(bufferedImage, cropWidth, cropHeight); } catch (Exception cropException) { - LOGGER.log(Level.WARNING, "Could not crop {0}: " + cropException.toString(), ImageUtils.getContentPathSafe(file)); //NOI18N NON-NLS + LOGGER.log(Level.WARNING, "Could not crop {0}: " + cropException.toString(), ImageUtils.getContentPathSafe(file)); //NON-NLS } } } catch (Exception e) { - LOGGER.log(Level.WARNING, "Could not scale {0}: " + e.toString(), ImageUtils.getContentPathSafe(file)); //NOI18N NON-NLS + LOGGER.log(Level.WARNING, "Could not scale {0}: " + e.toString(), ImageUtils.getContentPathSafe(file)); //NON-NLS throw e; } } @@ -733,19 +664,20 @@ public class ImageUtils { } ImageIO.write(thumbnail, FORMAT, cacheFile); } catch (IllegalArgumentException | IOException ex) { - LOGGER.log(Level.WARNING, "Could not write thumbnail for {0}: " + ex.toString(), ImageUtils.getContentPathSafe(file)); //NOI18N NON-NLS + LOGGER.log(Level.WARNING, "Could not write thumbnail for {0}: " + ex.toString(), ImageUtils.getContentPathSafe(file)); //NON-NLS } }); } } /** - * Create a new {@link Task} that will read the fileinto memory as an + * Create a new {@link Task} that will read the file into memory as an * {@link javafx.scene.image.Image} * * Note: the returned task is suitable for running in a background thread, * but is not started automatically. Clients are responsible for running the - * task, monitoring its progress, and using its result. + * task, monitoring its progress, and using its result(including testing for + * null). * * @param file the file to read as an Image * @@ -779,7 +711,7 @@ public class ImageUtils { */ static private abstract class ReadImageTaskBase extends Task implements IIOReadProgressListener { - private static final String IMAGEIO_COULD_NOT_READ_UNSUPPORTE_OR_CORRUPT = "ImageIO could not read {0}. It may be unsupported or corrupt"; //NOI18N NON-NLS + private static final String IMAGEIO_COULD_NOT_READ_UNSUPPORTE_OR_CORRUPT = "ImageIO could not read {0}. It may be unsupported or corrupt"; //NON-NLS final AbstractFile file; // private ImageReader reader; @@ -815,7 +747,7 @@ public class ImageUtils { try { bufferedImage = imageReader.read(0, param); //should always be same bufferedImage object } catch (IOException iOException) { - LOGGER.log(Level.WARNING, IMAGEIO_COULD_NOT_READ_UNSUPPORTE_OR_CORRUPT + ": " + iOException.toString(), ImageUtils.getContentPathSafe(file)); //NOI18N + LOGGER.log(Level.WARNING, IMAGEIO_COULD_NOT_READ_UNSUPPORTE_OR_CORRUPT + ": " + iOException.toString(), ImageUtils.getContentPathSafe(file)); //NON-NLS } finally { imageReader.removeIIOReadProgressListener(ReadImageTaskBase.this); } @@ -901,15 +833,85 @@ public class ImageUtils { * * @param content * - * @return + * @return the unique path for the content, or if that fails, just the name. */ static String getContentPathSafe(Content content) { try { return content.getUniquePath(); } catch (TskCoreException tskCoreException) { String contentName = content.getName(); - LOGGER.log(Level.SEVERE, "Failed to get unique path for " + contentName, tskCoreException); //NOI18N NON-NLS + LOGGER.log(Level.SEVERE, "Failed to get unique path for " + contentName, tskCoreException); //NON-NLS return contentName; } } + + /** + * Get the default thumbnail, which is the icon for a file. Used when we can + * not generate content based thumbnail. + * + * @return + * + * @deprecated use {@link #getDefaultThumbnail() } instead. + */ + @Deprecated + public static Image getDefaultIcon() { + return getDefaultThumbnail(); + } + + /** + * Get a file object for where the cached icon should exist. The returned + * file may not exist. + * + * @param id + * + * @return + * + * @deprecated use {@link #getCachedThumbnailLocation(long) } instead + */ + @Deprecated + + public static File getFile(long id) { + return getCachedThumbnailLocation(id); + } + + /** + * Get a thumbnail of a specified size for the given image. Generates the + * thumbnail if it is not already cached. + * + * @param content + * @param iconSize + * + * @return a thumbnail for the given image or a default one if there was a + * problem making a thumbnail. + * + * @deprecated use {@link #getThumbnail(org.sleuthkit.datamodel.Content, int) + * } instead. + */ + @Nonnull + @Deprecated + public static BufferedImage getIcon(Content content, int iconSize) { + return getThumbnail(content, iconSize); + } + + /** + * Get a thumbnail of a specified size for the given image. Generates the + * thumbnail if it is not already cached. + * + * @param content + * @param iconSize + * + * @return File object for cached image. Is guaranteed to exist, as long as + * there was not an error generating or saving the thumbnail. + * + * @deprecated use {@link #getCachedThumbnailFile(org.sleuthkit.datamodel.Content, int) + * } instead. + * + */ + @Nullable + @Deprecated + public static File getIconFile(Content content, int iconSize) { + return getCachedThumbnailFile(content, iconSize); + + } + } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParser.java b/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParser.java index 7cef330e6e..f371bee622 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParser.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParser.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,14 +25,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.LnkEnums.CommonCLSIDS; import org.sleuthkit.autopsy.coreutils.LnkEnums.DriveType; import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; /** - * - * @author dfickling Parse lnk files using documentation from + * Parse lnk files using documentation from: * http://msdn.microsoft.com/en-us/library/dd871305(v=prot.13).aspx * http://msdn.microsoft.com/en-us/library/windows/desktop/cc144090(v=vs.85).aspx#unknown_74413 * http://blog.0x01000000.org/2010/08/10/lnk-parsing-youre-doing-it-wrong-i/ @@ -67,12 +65,12 @@ public class JLnkParser { int showCommand = bb.getInt(); short hotkey = bb.getShort(); bb.get(new byte[10]); // reserved (???) - List linkTargetIdList = new ArrayList(); + List linkTargetIdList = new ArrayList<>(); if ((linkFlags & LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) == LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) { int idListSize = bb.getShort(); int bytesRead = 0; - List linkTargetIdListBytes = new ArrayList(); + List linkTargetIdListBytes = new ArrayList<>(); while (true) { short itemIdSize = bb.getShort(); if (itemIdSize == 0) { @@ -82,7 +80,7 @@ public class JLnkParser { byte[] theArray = new byte[itemIdSize - 2]; bb.get(theArray); // an idlist data object linkTargetIdListBytes.add(theArray); - bytesRead = bytesRead + itemIdSize; + bytesRead += itemIdSize; } linkTargetIdList = parseLinkTargetIdList(linkTargetIdListBytes); } @@ -272,7 +270,7 @@ public class JLnkParser { } private List parseLinkTargetIdList(List idList) { - List ret = new ArrayList(); + List ret = new ArrayList<>(); if (!idList.isEmpty()) { CommonCLSIDS clsid = CommonCLSIDS.valueOf(Arrays.copyOfRange(idList.remove(0), 2, 18)); switch (clsid) { @@ -295,7 +293,7 @@ public class JLnkParser { } private List parsePathElements(List idList) { - List ret = new ArrayList(); + List ret = new ArrayList<>(); for (byte[] pathElement : idList) { ByteBuffer bb = ByteBuffer.wrap(pathElement); bb.order(ByteOrder.LITTLE_ENDIAN); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java b/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java index 9ba40b7a08..2d16c51cbb 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -60,7 +60,8 @@ public class UNCPathUtilities { /** * This method converts a passed in path to UNC if it is not already UNC. * The UNC path will end up in one of the following two forms: - * \\hostname\somefolder\otherfolder or \\IP_ADDRESS\somefolder\otherfolder + * "\\hostname\somefolder\otherfolder" or + * "\\IP_ADDRESS\somefolder\otherfolder" * * This is accomplished by checking the mapped drives list the operating * system maintains and substituting where required. If the drive of the @@ -167,9 +168,10 @@ public class UNCPathUtilities { /** * Takes a UNC path that may have an IP address in it and converts it to * hostname, if it can resolve the hostname. Given - * \\10.11.12.13\some\folder, the result will be \\TEDS_COMPUTER\some\folder - * if the IP address 10.11.12.13 belongs to a machine with the hostname - * TEDS_COMPUTER and the local machine is able to resolve the hostname. + * "\\10.11.12.13\some\folder", the result will be + * "\\TEDS_COMPUTER\some\folder" if the IP address 10.11.12.13 belongs to a + * machine with the hostname TEDS_COMPUTER and the local machine is able to + * resolve the hostname. * * @param inputPath the path to convert to a hostname UNC path * @@ -186,9 +188,10 @@ public class UNCPathUtilities { /** * Takes a UNC path that may have an IP address in it and converts it to * hostname, if it can resolve the hostname. Given - * \\10.11.12.13\some\folder, the result will be \\TEDS_COMPUTER\some\folder - * if the IP address 10.11.12.13 belongs to a machine with the hostname - * TEDS_COMPUTER and the local machine is able to resolve the hostname. + * "\\10.11.12.13\some\folder", the result will be + * "\\TEDS_COMPUTER\some\folder" if the IP address 10.11.12.13 belongs to a + * machine with the hostname TEDS_COMPUTER and the local machine is able to + * resolve the hostname. * * @param inputPath a String of the path to convert to a hostname UNC path * @@ -263,6 +266,11 @@ public class UNCPathUtilities { */ synchronized private Map getMappedDrives() { Map driveMap = new HashMap<>(); + + if (PlatformUtil.isWindowsOS() == false) { + return driveMap; + } + File mappedDrive = Paths.get(System.getenv(TEMP_FOLDER), nameString + MAPPED_DRIVES).toFile(); try { Files.deleteIfExists(mappedDrive.toPath()); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java index 58c61e955b..a48a109a7e 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java @@ -60,10 +60,17 @@ public class VideoUtils { "flm", "tmv", "4xm"); //NON-NLS private static final SortedSet SUPPORTED_VIDEO_MIME_TYPES = new TreeSet<>( - Arrays.asList("application/x-shockwave-flash", "video/x-m4v", "video/x-flv", "video/quicktime", "video/avi", "video/msvideo", "video/x-msvideo", //NON-NLS - "video/mp4", "video/x-ms-wmv", "video/mpeg", "video/asf")); //NON-NLS - - private static final List CONDITIONAL_MIME_TYPES = Arrays.asList("application/octet-stream"); //NON-NLS + Arrays.asList("application/x-shockwave-flash", + "video/x-m4v", + "video/x-flv", + "video/quicktime", + "video/avi", + "video/msvideo", + "video/x-msvideo", //NON-NLS + "video/mp4", + "video/x-ms-wmv", + "video/mpeg", + "video/asf")); //NON-NLS public static List getSupportedVideoExtensions() { return SUPPORTED_VIDEO_EXTENSIONS; @@ -89,7 +96,7 @@ public class VideoUtils { } public static boolean isVideoThumbnailSupported(AbstractFile file) { - return isMediaThumbnailSupported(file, SUPPORTED_VIDEO_MIME_TYPES, SUPPORTED_VIDEO_EXTENSIONS, CONDITIONAL_MIME_TYPES); + return isMediaThumbnailSupported(file, "video/", SUPPORTED_VIDEO_MIME_TYPES, SUPPORTED_VIDEO_EXTENSIONS); } @NbBundle.Messages({"# {0} - file name", diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java index db8607cd93..fa59de87c1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2013 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -50,6 +50,7 @@ public class ArtifactStringContent implements StringContent { } @Override + @SuppressWarnings("deprecation") public String getString() { if (stringContent.isEmpty()) { try { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 7101b3c023..afeacb9a46 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -286,25 +286,19 @@ public class BlackboardArtifactNode extends DisplayableItemNode { * are put * @param artifact to extract properties from */ - @SuppressWarnings("deprecation") // TODO: Remove this when TSK_TAGGED_ARTIFACT rows are removed in a database upgrade. + @SuppressWarnings("deprecation") private void fillPropertyMap(Map map, BlackboardArtifact artifact) { try { for (BlackboardAttribute attribute : artifact.getAttributes()) { - final int attributeTypeID = attribute.getAttributeTypeID(); + final int attributeTypeID = attribute.getAttributeType().getTypeID(); //skip some internal attributes that user shouldn't see if (attributeTypeID == ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - } else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()) { - map.put(attribute.getAttributeTypeDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated)); + continue; + } else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { + map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated)); } else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID() && attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) { /* @@ -318,9 +312,9 @@ public class BlackboardArtifactNode extends DisplayableItemNode { if (value.length() > 512) { value = value.substring(0, 512); } - map.put(attribute.getAttributeTypeDisplayName(), value); + map.put(attribute.getAttributeType().getDisplayName(), value); } else { - map.put(attribute.getAttributeTypeDisplayName(), attribute.getDisplayString()); + map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString()); } } } catch (TskException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 146c4c72e5..8a9b31936f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -210,29 +210,17 @@ public class ExtractedContent implements AutopsyVisitableItem { // these are shown in other parts of the UI tree doNotShow.add(new BlackboardArtifact.Type( - BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO.getTypeID(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO.getLabel(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO.getDisplayName())); + BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO)); doNotShow.add(new BlackboardArtifact.Type( - BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getLabel(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName())); + BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG)); doNotShow.add(new BlackboardArtifact.Type( - BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getLabel(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT)); doNotShow.add(new BlackboardArtifact.Type( - BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getLabel(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT)); doNotShow.add(new BlackboardArtifact.Type( - BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getLabel(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName())); + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)); doNotShow.add(new BlackboardArtifact.Type( - BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getLabel(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName())); + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT)); } private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index d740149ffe..8b54e5a7b6 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; @@ -110,70 +111,52 @@ public class FileNode extends AbstractFsContentNode { // file based off it's extension static String getIconForFileType(AbstractFile file) { // Get the name, extension - String name = file.getName(); - int dotIndex = name.lastIndexOf("."); - if (dotIndex == -1) { - return "org/sleuthkit/autopsy/images/file-icon.png"; //NON-NLS - } - String ext = name.substring(dotIndex).toLowerCase(); + String ext = file.getNameExtension(); - // Images - for (String s : FileTypeExtensions.getImageExtensions()) { - if (ImageUtils.thumbnailSupported(file) || ext.equals(s)) { - return "org/sleuthkit/autopsy/images/image-file.png"; //NON-NLS - } + if (StringUtils.isBlank(ext)) { + return "org/sleuthkit/autopsy/images/file-icon.png"; //NON-NLS + } else { + ext = "." + ext; + } + + if (ImageUtils.isImageThumbnailSupported(file) + || FileTypeExtensions.getImageExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/image-file.png"; //NON-NLS } // Videos - for (String s : FileTypeExtensions.getVideoExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/video-file.png"; //NON-NLS - } + if (FileTypeExtensions.getVideoExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/video-file.png"; //NON-NLS } // Audio Files - for (String s : FileTypeExtensions.getAudioExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/audio-file.png"; //NON-NLS - } + if (FileTypeExtensions.getAudioExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/audio-file.png"; //NON-NLS } // Documents - for (String s : FileTypeExtensions.getDocumentExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/doc-file.png"; //NON-NLS - } + if (FileTypeExtensions.getDocumentExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/doc-file.png"; //NON-NLS } // Executables / System Files - for (String s : FileTypeExtensions.getExecutableExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/exe-file.png"; //NON-NLS - } + if (FileTypeExtensions.getExecutableExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/exe-file.png"; //NON-NLS } // Text Files - for (String s : FileTypeExtensions.getTextExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/text-file.png"; //NON-NLS - } + if (FileTypeExtensions.getTextExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/text-file.png"; //NON-NLS } // Web Files - for (String s : FileTypeExtensions.getWebExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/web-file.png"; //NON-NLS - } + if (FileTypeExtensions.getWebExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/web-file.png"; //NON-NLS } // PDFs - for (String s : FileTypeExtensions.getPDFExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/pdf-file.png"; //NON-NLS - } + if (FileTypeExtensions.getPDFExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/pdf-file.png"; //NON-NLS } // Archives - for (String s : FileTypeExtensions.getArchiveExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/archive-file.png"; //NON-NLS - } + if (FileTypeExtensions.getArchiveExtensions().contains(ext)) { + return "org/sleuthkit/autopsy/images/archive-file.png"; //NON-NLS } // Else return the default return "org/sleuthkit/autopsy/images/file-icon.png"; //NON-NLS - } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 16bb0b591d..f908251d28 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -55,7 +55,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; @@ -34,7 +33,6 @@ import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.ErrorInfo; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.ingest.IngestModule; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -69,11 +67,12 @@ public final class ExternalResultsImporter { * Import results generated by a process external to Autopsy into Autopsy. * * @param results A standard representation of results data (e.g., - * artifacts, derived files, reports)from the data source. + * artifacts, derived files, reports)from the data source. * * @return A collection of error messages, possibly empty. The error - * messages are already logged but are provided to allow the caller to - * provide additional user feedback via the Autopsy user interface. + * messages are already logged but are provided to allow the caller + * to provide additional user feedback via the Autopsy user + * interface. */ public List importResults(ExternalResults results) { blackboard = Case.getCurrentCase().getServices().getBlackboard(); @@ -133,7 +132,7 @@ public final class ExternalResultsImporter { for (ExternalResults.Artifact artifactData : results.getArtifacts()) { try { // Add the artifact to the case database. - int artifactTypeId = caseDb.getArtifactTypeID(artifactData.getType()); + int artifactTypeId = caseDb.getArtifactType(artifactData.getType()).getTypeID(); if (artifactTypeId == -1) { artifactTypeId = caseDb.addBlackboardArtifactType(artifactData.getType(), artifactData.getType()).getTypeID(); } @@ -147,20 +146,20 @@ public final class ExternalResultsImporter { BlackboardAttribute.Type attributeType = caseDb.getAttributeType(attributeData.getType()); if (attributeType == null) { switch (attributeData.getValueType()) { - case "text": //NON-NLS - attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("String"), attributeData.getType()); //NON-NLS - break; - case "int32": //NON-NLS - attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Integer"), attributeData.getType()); //NON-NLS - break; - case "int64": //NON-NLS - attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Long"), attributeData.getType()); //NON-NLS - break; - case "double": //NON-NLS - attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Double"), attributeData.getType()); //NON-NLS - break; - case "datetime": //NON-NLS - attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("DateTime"), attributeData.getType()); //NON-NLS + case "text": //NON-NLS + attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("String"), attributeData.getType()); //NON-NLS + break; + case "int32": //NON-NLS + attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Integer"), attributeData.getType()); //NON-NLS + break; + case "int64": //NON-NLS + attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Long"), attributeData.getType()); //NON-NLS + break; + case "double": //NON-NLS + attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Double"), attributeData.getType()); //NON-NLS + break; + case "datetime": //NON-NLS + attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("DateTime"), attributeData.getType()); //NON-NLS } } @@ -216,13 +215,7 @@ public final class ExternalResultsImporter { ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage); this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage)); } - } catch (TskCoreException ex) { - String errorMessage = NbBundle.getMessage(this.getClass(), - "ExternalResultsImporter.importArtifacts.errMsg2.text", - artifactData.getType(), artifactData.getSourceFilePath()); - ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex); - this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex)); - } catch (TskDataException ex) { + } catch (TskCoreException | TskDataException ex) { String errorMessage = NbBundle.getMessage(this.getClass(), "ExternalResultsImporter.importArtifacts.errMsg2.text", artifactData.getType(), artifactData.getSourceFilePath()); @@ -299,15 +292,6 @@ public final class ExternalResultsImporter { return relativePath; } -// private static boolean isStandardArtifactType(int artifactTypeId) { -// for (BlackboardArtifact.ARTIFACT_TYPE art : BlackboardArtifact.ARTIFACT_TYPE.values()) { -// if (art.getTypeID() == artifactTypeId) { -// return true; -// } -// } -// return false; -// } -// private void recordError(String errorMessage) { ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage); this.errors.add(new ErrorInfo(this.getClass().getName(), errorMessage)); diff --git a/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsXMLParser.java b/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsXMLParser.java index 8443e6b71a..0c33e87ca7 100644 --- a/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsXMLParser.java +++ b/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsXMLParser.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"); @@ -117,6 +117,7 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser { /** * Constructor. * + * @param dataSource The data source for the results. * @param resultsFilePath Full path of the results file to be parsed. */ public ExternalResultsXMLParser(Content dataSource, String resultsFilePath) { diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties index 99c61a24ca..d946e2f9c2 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties @@ -18,7 +18,7 @@ DateSearchPanel.jLabel1.text=to DateSearchPanel.dateFromTextField.text= DateSearchPanel.dateFromButtonCalendar.text= NameSearchPanel.nameCheckBox.text=Name: -NameSearchPanel.noteNameLabel.text=*Note: Name match is case insensitive and matches
any part of the file name. Regular expressions are
not currently supported. +NameSearchPanel.noteNameLabel.text=*Note: Name match is case insensitive and matches any part of the file name. Regular expressions are not currently supported. NameSearchPanel.searchTextField.text= SizeSearchPanel.sizeCheckBox.text=Size: NameSearchPanel.cutMenuItem.text=Cut @@ -40,7 +40,6 @@ FileSearchPanel.custComp.label.text=Search for files that match the following cr FileSearchPanel.filterTitle.name=Name FileSearchPanel.filterTitle.metadata=Metadata FileSearchPanel.filterTitle.knownStatus=Known Status -FileSearchPanel.searchButton.text=Search FileSearchPanel.search.results.title=File Search Results {0} FileSearchPanel.search.results.pathText=Filename Search Results\: FileSearchPanel.search.results.msg=File Search\: {0} matches found @@ -54,3 +53,6 @@ SearchNode.getName.text=Search Result SizeSearchPanel.sizeCompareComboBox.equalTo=equal to SizeSearchPanel.sizeCompareComboBox.greaterThan=greater than SizeSearchPanel.sizeCompareComboBox.lessThan=less than +MimeTypePanel.jCheckBox1.text=MIME Type: +MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected +FileSearchPanel.searchButton.text=Search diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle_ja.properties index 891bf77b29..401f521568 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle_ja.properties @@ -1,51 +1,50 @@ -OpenIDE-Module-Name=\u30D5\u30A1\u30A4\u30EB\u691C\u7D22 -KnownStatusSearchPanel.knownCheckBox.text=\u65E2\u77E5\u30B9\u30C6\u30FC\u30BF\u30B9\uFF1A -KnownStatusSearchPanel.knownBadOptionCheckBox.text=\u65E2\u77E5\u306E\u60AA\u8CEA -KnownStatusSearchPanel.knownOptionCheckBox.text=\u65E2\u77E5\uFF08NSRL\u307E\u305F\u306F\u305D\u306E\u4ED6\uFF09 -KnownStatusSearchPanel.unknownOptionCheckBox.text=\u4E0D\u660E -DateSearchFilter.noneSelectedMsg.text=\u6700\u4F4E\u4E00\u3064\u306E\u30C7\u30FC\u30BF\u30BF\u30A4\u30D7\u3092\u9078\u629E\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF01 -DateSearchPanel.dateCheckBox.text=\u65E5\u4ED8\uFF1A -DateSearchPanel.jLabel4.text=\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3\uFF1A -DateSearchPanel.jLabel3.text=*\u65E5\u4ED8\u306E\u5F62\u5F0F\u306Fmm/dd/yyyy -DateSearchPanel.jLabel2.text=*\u7A7A\u767D\u306E\u9805\u76EE\u306F\u300C\u5236\u9650\u306A\u3057\u300D\u3068\u3044\u3046\u610F\u5473\u3067\u3059 -DateSearchPanel.createdCheckBox.text=\u4F5C\u6210\u6E08\u307F -DateSearchPanel.accessedCheckBox.text=\u30A2\u30AF\u30BB\u30B9\u6E08\u307F -DateSearchPanel.changedCheckBox.text=\u5909\u66F4\u6E08\u307F -DateSearchPanel.modifiedCheckBox.text=\u4FEE\u6B63\u6E08\u307F +OpenIDE-Module-Name=\u30d5\u30a1\u30a4\u30eb\u691c\u7d22 +KnownStatusSearchPanel.knownCheckBox.text=\u65e2\u77e5\u30b9\u30c6\u30fc\u30bf\u30b9\uff1a +KnownStatusSearchPanel.knownBadOptionCheckBox.text=\u65e2\u77e5\u306e\u60aa\u8cea +KnownStatusSearchPanel.knownOptionCheckBox.text=\u65e2\u77e5\uff08NSRL\u307e\u305f\u306f\u305d\u306e\u4ed6\uff09 +KnownStatusSearchPanel.unknownOptionCheckBox.text=\u4e0d\u660e +DateSearchFilter.noneSelectedMsg.text=\u6700\u4f4e\u4e00\u3064\u306e\u30c7\u30fc\u30bf\u30bf\u30a4\u30d7\u3092\u9078\u629e\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\uff01 +DateSearchPanel.dateCheckBox.text=\u65e5\u4ed8\uff1a +DateSearchPanel.jLabel4.text=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\uff1a +DateSearchPanel.jLabel3.text=*\u65e5\u4ed8\u306e\u5f62\u5f0f\u306fmm/dd/yyyy +DateSearchPanel.jLabel2.text=*\u7a7a\u767d\u306e\u9805\u76ee\u306f\u300c\u5236\u9650\u306a\u3057\u300d\u3068\u3044\u3046\u610f\u5473\u3067\u3059 +DateSearchPanel.createdCheckBox.text=\u4f5c\u6210\u6e08\u307f +DateSearchPanel.accessedCheckBox.text=\u30a2\u30af\u30bb\u30b9\u6e08\u307f +DateSearchPanel.changedCheckBox.text=\u5909\u66f4\u6e08\u307f +DateSearchPanel.modifiedCheckBox.text=\u4fee\u6b63\u6e08\u307f DateSearchPanel.jLabel1.text=to -NameSearchPanel.nameCheckBox.text=\u540D\u524D\uFF1A -NameSearchPanel.noteNameLabel.text=*\u6CE8\u610F\uFF1A\u540D\u524D\u30DE\u30C3\u30C1\u306F\u5927\u6587\u5B57\u3068\u5C0F\u6587\u5B57\u3092\u533A\u5225\u3057\u307E\u3059\u3002\u307E\u305F\u3001
\u30D5\u30A1\u30A4\u30EB\u540D\u306E\u3044\u304B\u306A\u308B\u90E8\u5206\u3082\u30DE\u30C3\u30C1\u3057\u307E\u3059\u3002\u6B63\u898F\u8868\u73FE\u306F
\u73FE\u5728\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002 -SizeSearchPanel.sizeCheckBox.text=\u30B5\u30A4\u30BA\uFF1A -NameSearchPanel.cutMenuItem.text=\u30AB\u30C3\u30C8 -NameSearchPanel.copyMenuItem.text=\u30B3\u30D4\u30FC -NameSearchPanel.pasteMenuItem.text=\u8CBC\u308A\u4ED8\u3051 -NameSearchPanel.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E -SizeSearchPanel.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E -SizeSearchPanel.pasteMenuItem.text=\u8CBC\u308A\u4ED8\u3051 -SizeSearchPanel.copyMenuItem.text=\u30B3\u30D4\u30FC -SizeSearchPanel.cutMenuItem.text=\u30AB\u30C3\u30C8 -DateSearchPanel.cutMenuItem.text=\u30AB\u30C3\u30C8 -DateSearchPanel.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E -DateSearchPanel.pasteMenuItem.text=\u8CBC\u308A\u4ED8\u3051 -DateSearchPanel.copyMenuItem.text=\u30B3\u30D4\u30FC -FileSearchAction.getName.text=\u5C5E\u6027\u306B\u3088\u308B\u30D5\u30A1\u30A4\u30EB\u691C\u7D22 -FileSearchDialog.frame.title=\u5C5E\u6027\u306B\u3088\u308B\u30D5\u30A1\u30A4\u30EB\u691C\u7D22 -FileSearchDialog.frame.msg=\u5C5E\u6027\u306B\u3088\u308B\u30D5\u30A1\u30A4\u30EB\u691C\u7D22 -FileSearchPanel.custComp.label.text=\u6B21\u306E\u6761\u4EF6\u306B\u4E00\u81F4\u3059\u308B\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\uFF1A -FileSearchPanel.filterTitle.name=\u540D\u524D -FileSearchPanel.filterTitle.metadata=\u30E1\u30BF\u30C7\u30FC\u30BF -FileSearchPanel.filterTitle.knownStatus=\u65E2\u77E5\u30B9\u30C6\u30FC\u30BF\u30B9 -FileSearchPanel.searchButton.text=\u691C\u7D22 -FileSearchPanel.search.results.title=\u30D5\u30A1\u30A4\u30EB\u691C\u7D22\u7D50\u679C{0} -FileSearchPanel.search.results.pathText=\u30D5\u30A1\u30A4\u30EB\u540D\u691C\u7D22\u7D50\u679C\uFF1A -FileSearchPanel.search.results.msg=\u30D5\u30A1\u30A4\u30EB\u691C\u7D22\uFF1A{0}\u500B\u306E\u30DE\u30C3\u30C1\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F -FileSearchPanel.search.results.details=\u591A\u304F\u306E\u30DE\u30C3\u30C1\u304C\u3042\u308B\u5834\u5408\u3001\u4E00\u90E8\u306E\u51E6\u7406\u306E\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9\u306B\u5F71\u97FF\u3092\u4E0E\u3048\u308B\u304B\u3082\u3057\u308C\u307E\u305B\u3093 -FileSearchPanel.search.exception.noFilterSelected.msg=\u6700\u4F4E\uFF11\u500B\u306E\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u9078\u629E\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -FileSearchPanel.search.validationErr.msg=\u30D0\u30EA\u30C7\u30FC\u30B7\u30E7\u30F3\u30A8\u30E9\u30FC\uFF1A{0} -FileSearchPanel.emptyWhereClause.text=\u7121\u52B9\u306A\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u3059\u3002\u8868\u793A\u3059\u308B\u3082\u306E\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -KnownStatusSearchFilter.noneSelectedMsg.text=\u6700\u4F4E\uFF11\u500B\u306E\u65E2\u77E5\u30B9\u30C6\u30FC\u30BF\u30B9\u3092\u9078\u629E\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF01 -NameSearchFilter.emptyNameMsg.text=\u540D\u524D\u691C\u7D22\u306B\u4F55\u304B\u8A18\u5165\u3057\u306A\u3051\u308C\u3070\u3044\u3051\u307E\u305B\u3093\u3002 -SearchNode.getName.text=\u691C\u7D22\u7D50\u679C -SizeSearchPanel.sizeCompareComboBox.equalTo=\u4E0B\u8A18\u3068\u7B49\u3057\u3044 -SizeSearchPanel.sizeCompareComboBox.greaterThan=\u4E0B\u8A18\u3088\u308A\u5927\u304D\u3044 -SizeSearchPanel.sizeCompareComboBox.lessThan=\u4E0B\u8A18\u3088\u308A\u5C0F\u3055\u3044 +NameSearchPanel.nameCheckBox.text=\u540d\u524d\uff1a +NameSearchPanel.noteNameLabel.text=*\u6ce8\u610f\uff1a\u540d\u524d\u30de\u30c3\u30c1\u306f\u5927\u6587\u5b57\u3068\u5c0f\u6587\u5b57\u3092\u533a\u5225\u3057\u307e\u3059\u3002\u307e\u305f\u3001
\u30d5\u30a1\u30a4\u30eb\u540d\u306e\u3044\u304b\u306a\u308b\u90e8\u5206\u3082\u30de\u30c3\u30c1\u3057\u307e\u3059\u3002\u6b63\u898f\u8868\u73fe\u306f
\u73fe\u5728\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 +SizeSearchPanel.sizeCheckBox.text=\u30b5\u30a4\u30ba\uff1a +NameSearchPanel.cutMenuItem.text=\u30ab\u30c3\u30c8 +NameSearchPanel.copyMenuItem.text=\u30b3\u30d4\u30fc +NameSearchPanel.pasteMenuItem.text=\u8cbc\u308a\u4ed8\u3051 +NameSearchPanel.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e +SizeSearchPanel.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e +SizeSearchPanel.pasteMenuItem.text=\u8cbc\u308a\u4ed8\u3051 +SizeSearchPanel.copyMenuItem.text=\u30b3\u30d4\u30fc +SizeSearchPanel.cutMenuItem.text=\u30ab\u30c3\u30c8 +DateSearchPanel.cutMenuItem.text=\u30ab\u30c3\u30c8 +DateSearchPanel.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e +DateSearchPanel.pasteMenuItem.text=\u8cbc\u308a\u4ed8\u3051 +DateSearchPanel.copyMenuItem.text=\u30b3\u30d4\u30fc +FileSearchAction.getName.text=\u5c5e\u6027\u306b\u3088\u308b\u30d5\u30a1\u30a4\u30eb\u691c\u7d22 +FileSearchDialog.frame.title=\u5c5e\u6027\u306b\u3088\u308b\u30d5\u30a1\u30a4\u30eb\u691c\u7d22 +FileSearchDialog.frame.msg=\u5c5e\u6027\u306b\u3088\u308b\u30d5\u30a1\u30a4\u30eb\u691c\u7d22 +FileSearchPanel.custComp.label.text=\u6b21\u306e\u6761\u4ef6\u306b\u4e00\u81f4\u3059\u308b\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22\uff1a +FileSearchPanel.filterTitle.name=\u540d\u524d +FileSearchPanel.filterTitle.metadata=\u30e1\u30bf\u30c7\u30fc\u30bf +FileSearchPanel.filterTitle.knownStatus=\u65e2\u77e5\u30b9\u30c6\u30fc\u30bf\u30b9 +FileSearchPanel.search.results.title=\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u7d50\u679c{0} +FileSearchPanel.search.results.pathText=\u30d5\u30a1\u30a4\u30eb\u540d\u691c\u7d22\u7d50\u679c\uff1a +FileSearchPanel.search.results.msg=\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\uff1a{0}\u500b\u306e\u30de\u30c3\u30c1\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f +FileSearchPanel.search.results.details=\u591a\u304f\u306e\u30de\u30c3\u30c1\u304c\u3042\u308b\u5834\u5408\u3001\u4e00\u90e8\u306e\u51e6\u7406\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u306b\u5f71\u97ff\u3092\u4e0e\u3048\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093 +FileSearchPanel.search.exception.noFilterSelected.msg=\u6700\u4f4e\uff11\u500b\u306e\u30d5\u30a3\u30eb\u30bf\u30fc\u3092\u9078\u629e\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +FileSearchPanel.search.validationErr.msg=\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u30a8\u30e9\u30fc\uff1a{0} +FileSearchPanel.emptyWhereClause.text=\u7121\u52b9\u306a\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u3059\u3002\u8868\u793a\u3059\u308b\u3082\u306e\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +KnownStatusSearchFilter.noneSelectedMsg.text=\u6700\u4f4e\uff11\u500b\u306e\u65e2\u77e5\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u9078\u629e\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\uff01 +NameSearchFilter.emptyNameMsg.text=\u540d\u524d\u691c\u7d22\u306b\u4f55\u304b\u8a18\u5165\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u3002 +SearchNode.getName.text=\u691c\u7d22\u7d50\u679c +SizeSearchPanel.sizeCompareComboBox.equalTo=\u4e0b\u8a18\u3068\u7b49\u3057\u3044 +SizeSearchPanel.sizeCompareComboBox.greaterThan=\u4e0b\u8a18\u3088\u308a\u5927\u304d\u3044 +SizeSearchPanel.sizeCompareComboBox.lessThan=\u4e0b\u8a18\u3088\u308a\u5c0f\u3055\u3044 diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form index 0418d2eec7..4b253ff1e6 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form @@ -55,86 +55,93 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - + + + + + + + + + + + + + + + - - - - - + + + + + + + + - - - - + + + + + + + - - - - + + + + + + + + + + + + + + + - - - - - - - + + + + + + - - - - - - - - - - + @@ -188,6 +195,9 @@ + + + @@ -208,6 +218,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index 91a63186ed..b2bb6d295c 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -74,7 +74,6 @@ class DateSearchPanel extends javax.swing.JPanel { copyMenuItem.addActionListener(actList); pasteMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList); - } JCheckBox getAccessedCheckBox() { @@ -172,6 +171,7 @@ class DateSearchPanel extends javax.swing.JPanel { dateCheckBox.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateCheckBox.text")); // NOI18N + jLabel3.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N jLabel3.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel3.text")); // NOI18N dateFromTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateFromTextField.text")); // NOI18N @@ -181,6 +181,7 @@ class DateSearchPanel extends javax.swing.JPanel { } }); + jLabel2.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N jLabel2.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel2.text")); // NOI18N modifiedCheckBox.setSelected(true); @@ -214,69 +215,74 @@ class DateSearchPanel extends javax.swing.JPanel { layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(dateCheckBox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(dateFromTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(dateFromButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(dateToTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(dateToButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addGap(21, 21, 21) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(changedCheckBox) - .addComponent(modifiedCheckBox)) + .addComponent(dateCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(dateFromTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(dateFromButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(accessedCheckBox) - .addComponent(createdCheckBox))) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(dateToTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(dateToButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel3))) + .addContainerGap(26, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jLabel4) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 193, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() - .addGap(21, 21, 21) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel3) - .addComponent(jLabel2))))) + .addComponent(modifiedCheckBox) + .addGap(6, 6, 6) + .addComponent(accessedCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(createdCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(changedCheckBox))) + .addGap(33, 33, 33)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(dateCheckBox) - .addComponent(dateFromTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(dateToButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(dateToTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(dateFromButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(4, 4, 4) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(dateCheckBox) + .addComponent(dateFromTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dateToButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(dateToTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(dateFromButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel3) + .addComponent(jLabel2)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel4) .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addComponent(modifiedCheckBox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(changedCheckBox)) - .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(modifiedCheckBox, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(accessedCheckBox) - .addGap(23, 23, 23)) - .addComponent(createdCheckBox)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel3) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(createdCheckBox) + .addComponent(changedCheckBox))) + .addGap(0, 0, 0)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form index 7c2a63a271..dbb90bea12 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form @@ -1,6 +1,11 @@
+ + + + + @@ -16,13 +21,48 @@ - + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index a8ee427c24..e796589d22 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -60,8 +60,7 @@ import org.sleuthkit.datamodel.TskCoreException; */ class FileSearchPanel extends javax.swing.JPanel { - private List filterAreas = new ArrayList(); - private JButton searchButton; + private final List filterAreas = new ArrayList<>(); private static int resultWindowCount = 0; //keep track of result windows so they get unique names private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text"); @@ -79,14 +78,6 @@ class FileSearchPanel extends javax.swing.JPanel { */ private void customizeComponents() { - this.setLayout(new BorderLayout()); - - JPanel filterPanel = new JPanel(); - filterPanel.setLayout(new BoxLayout(filterPanel, BoxLayout.Y_AXIS)); - filterPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); - - this.add(filterPanel, BorderLayout.CENTER); - JLabel label = new JLabel(NbBundle.getMessage(this.getClass(), "FileSearchPanel.custComp.label.text")); label.setAlignmentX(Component.LEFT_ALIGNMENT); label.setBorder(new EmptyBorder(0, 0, 10, 0)); @@ -95,8 +86,9 @@ class FileSearchPanel extends javax.swing.JPanel { // Create and add filter areas this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.name"), new NameSearchFilter())); - List metadataFilters = new ArrayList(); + List metadataFilters = new ArrayList<>(); metadataFilters.add(new SizeSearchFilter()); + metadataFilters.add(new MimeTypeFilter()); metadataFilters.add(new DateSearchFilter()); this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), metadataFilters)); @@ -108,11 +100,6 @@ class FileSearchPanel extends javax.swing.JPanel { filterPanel.add(fa); } - // Create and add search button - this.searchButton = new JButton(NbBundle.getMessage(this.getClass(), "FileSearchPanel.searchButton.text")); - this.searchButton.setAlignmentX(Component.LEFT_ALIGNMENT); - filterPanel.add(searchButton); - addListenerToAll(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -234,7 +221,7 @@ class FileSearchPanel extends javax.swing.JPanel { } private Collection getFilters() { - Collection filters = new ArrayList(); + Collection filters = new ArrayList<>(); for (FilterArea fa : this.filterAreas) { filters.addAll(fa.getFilters()); @@ -244,7 +231,7 @@ class FileSearchPanel extends javax.swing.JPanel { } private Collection getEnabledFilters() { - Collection enabledFilters = new ArrayList(); + Collection enabledFilters = new ArrayList<>(); for (FileSearchFilter f : this.getFilters()) { if (f.isEnabled()) { @@ -273,17 +260,38 @@ class FileSearchPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { + filterPanel = new javax.swing.JPanel(); + searchButton = new javax.swing.JButton(); + + setPreferredSize(new java.awt.Dimension(300, 300)); + + filterPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); + filterPanel.setPreferredSize(new java.awt.Dimension(300, 400)); + filterPanel.setLayout(new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS)); + + searchButton.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) + .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(searchButton) + .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 376, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0) + .addComponent(searchButton) + .addContainerGap()) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel filterPanel; + private javax.swing.JButton searchButton; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FilterArea.java b/Core/src/org/sleuthkit/autopsy/filesearch/FilterArea.java index 6c9329ca11..430fb47e5e 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FilterArea.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FilterArea.java @@ -92,20 +92,22 @@ class FilterArea extends JPanel { filtersPanel = new JPanel(); filtersPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - BoxLayout filtersPanelLayout = new BoxLayout(filtersPanel, BoxLayout.Y_AXIS); - filtersPanel.setLayout(filtersPanelLayout); + BoxLayout filtersPanelLayout = new BoxLayout(this, BoxLayout.Y_AXIS); + this.setLayout(filtersPanelLayout); - for (FileSearchFilter f : filters) { + for (int i = 0; i < filters.size(); i++) { + FileSearchFilter f = filters.get(i); JComponent filterComponent = f.getComponent(); filterComponent.setAlignmentX(Component.LEFT_ALIGNMENT); - filterComponent.setBorder(new EmptyBorder(0, 0, 20, 0)); - filtersPanel.add(filterComponent); + if (i != filters.size() - 1) { + filterComponent.setBorder(new EmptyBorder(0, 0, 15, 0)); + } + else { + filterComponent.setBorder(new EmptyBorder(0, 0, 18, 0)); + } + this.add(filterComponent); } - - this.add(filtersPanel); - - BoxLayout layout = new BoxLayout(this, BoxLayout.Y_AXIS); - this.setLayout(layout); + this.setAlignmentX(Component.LEFT_ALIGNMENT); } private void refresh() { diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.form index 3237a70996..3de5bd4680 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.form @@ -16,14 +16,19 @@ - - - + - - - + + + + + + + + + + @@ -32,11 +37,11 @@ - - - - - + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java index c2866caacd..9a564fcdbc 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java @@ -89,24 +89,27 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(knownCheckBox) .addGroup(layout.createSequentialGroup() - .addGap(21, 21, 21) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(knownBadOptionCheckBox) - .addComponent(unknownOptionCheckBox) - .addComponent(knownOptionCheckBox))) + .addComponent(knownCheckBox) + .addGroup(layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(unknownOptionCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownOptionCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownBadOptionCheckBox))) + .addContainerGap(28, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(knownCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(unknownOptionCheckBox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownOptionCheckBox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownBadOptionCheckBox)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(unknownOptionCheckBox) + .addComponent(knownOptionCheckBox) + .addComponent(knownBadOptionCheckBox))) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypeFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypeFilter.java new file mode 100755 index 0000000000..b119566299 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypeFilter.java @@ -0,0 +1,44 @@ +/* + * 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. + */ +package org.sleuthkit.autopsy.filesearch; + +import java.awt.event.ActionListener; + +/** + * Filter by mime type used in filter areas of file search by attribute. + */ +class MimeTypeFilter extends AbstractFileSearchFilter { + + public MimeTypeFilter(MimeTypePanel component) { + super(component); + } + public MimeTypeFilter() { + this(new MimeTypePanel()); + } + + @Override + public boolean isEnabled() { + return this.getComponent().isSelected() && + !this.getComponent().getMimeTypesSelected().isEmpty(); + } + + @Override + public String getPredicate() throws FilterValidationException { + String predicate = ""; + for(String mimeType : this.getComponent().getMimeTypesSelected()) { + predicate += "mime_type = '" + mimeType + "' OR "; + } + if(predicate.length() > 3) { + predicate = predicate.substring(0, predicate.length() - 3); + } + return predicate; + } + + @Override + public void addActionListener(ActionListener l) { + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.form new file mode 100755 index 0000000000..9221d39633 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.form @@ -0,0 +1,98 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.java new file mode 100755 index 0000000000..8a90761946 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.java @@ -0,0 +1,138 @@ +/* + * 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. + */ +package org.sleuthkit.autopsy.filesearch; + +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.logging.Level; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; +import org.apache.tika.mime.MediaType; +import org.apache.tika.mime.MimeTypes; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * + * @author oliver + */ +public class MimeTypePanel extends javax.swing.JPanel { + + private static final SortedSet mediaTypes = MimeTypes.getDefaultMimeTypes().getMediaTypeRegistry().getTypes(); + private static final Logger logger = Logger.getLogger(MimeTypePanel.class.getName()); + private static final long serialVersionUID = 1L; + + /** + * Creates new form MimeTypePanel + */ + public MimeTypePanel() { + initComponents(); + } + + private String[] getMimeTypeArray() { + Set fileTypesCollated = new HashSet<>(); + for (MediaType mediaType : mediaTypes) { + fileTypesCollated.add(mediaType.toString()); + } + + FileTypeDetector fileTypeDetector; + try { + fileTypeDetector = new FileTypeDetector(); + List userDefinedFileTypes = fileTypeDetector.getUserDefinedTypes(); + fileTypesCollated.addAll(userDefinedFileTypes); + + } catch (FileTypeDetector.FileTypeDetectorInitException ex) { + logger.log(Level.SEVERE, "Unable to get user defined file types", ex); + } + + List toSort = new ArrayList<>(fileTypesCollated); + toSort.sort((String string1, String string2) -> { + int result = String.CASE_INSENSITIVE_ORDER.compare(string1, string2); + if (result == 0) { + result = string1.compareTo(string2); + } + return result; + }); + String[] mimeTypeArray = new String[toSort.size()]; + return toSort.toArray(mimeTypeArray); + } + + List getMimeTypesSelected() { + return this.jList1.getSelectedValuesList(); + } + + boolean isSelected() { + return this.jCheckBox1.isSelected(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jScrollPane1 = new javax.swing.JScrollPane(); + jList1 = new javax.swing.JList(); + jCheckBox1 = new javax.swing.JCheckBox(); + jLabel1 = new javax.swing.JLabel(); + + setMinimumSize(new java.awt.Dimension(150, 150)); + setPreferredSize(new java.awt.Dimension(100, 100)); + + jList1.setModel(new javax.swing.AbstractListModel() { + String[] strings = getMimeTypeArray(); + public int getSize() { return strings.length; } + public String getElementAt(int i) { return strings[i]; } + }); + jList1.setMinimumSize(new java.awt.Dimension(0, 200)); + jScrollPane1.setViewportView(jList1); + + org.openide.awt.Mnemonics.setLocalizedText(jCheckBox1, org.openide.util.NbBundle.getMessage(MimeTypePanel.class, "MimeTypePanel.jCheckBox1.text")); // NOI18N + + jLabel1.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(MimeTypePanel.class, "MimeTypePanel.jLabel1.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jCheckBox1) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 246, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(jCheckBox1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 106, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1) + .addGap(0, 0, 0)) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JCheckBox jCheckBox1; + private javax.swing.JLabel jLabel1; + private javax.swing.JList jList1; + private javax.swing.JScrollPane jScrollPane1; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.form index e28dd6d357..7b5e61f5e1 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.form @@ -55,18 +55,16 @@ - - + + + - - + - - - - + + @@ -79,6 +77,7 @@ + @@ -121,6 +120,15 @@ + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java index 7f59ec3e3b..dc68c320de 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java @@ -121,21 +121,23 @@ class NameSearchPanel extends javax.swing.JPanel { noteNameLabel.setFont(noteNameLabel.getFont().deriveFont(noteNameLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 10)); noteNameLabel.setText(org.openide.util.NbBundle.getMessage(NameSearchPanel.class, "NameSearchPanel.noteNameLabel.text")); // NOI18N + noteNameLabel.setMaximumSize(new java.awt.Dimension(250, 30)); + noteNameLabel.setMinimumSize(new java.awt.Dimension(250, 30)); + noteNameLabel.setPreferredSize(new java.awt.Dimension(250, 30)); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(nameCheckBox) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(layout.createSequentialGroup() - .addGap(12, 12, 12) - .addComponent(noteNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addGap(0, 0, 0) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(noteNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() + .addComponent(nameCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(searchTextField)))) + .addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 247, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, 0)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -144,7 +146,8 @@ class NameSearchPanel extends javax.swing.JPanel { .addComponent(nameCheckBox) .addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(noteNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(noteNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleProcessTerminator.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleProcessTerminator.java index 59b5af0730..eacb918d92 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleProcessTerminator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleProcessTerminator.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"); @@ -69,9 +69,6 @@ public final class DataSourceIngestModuleProcessTerminator implements ProcessTer } } - /** - * @inheritDoc - */ @Override public boolean shouldTerminateProcess() { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java index 4c27c201d5..363af546de 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -195,17 +195,11 @@ final class DataSourceIngestPipeline { return this.processingStartTime; } - /** - * @inheritDoc - */ @Override public void startUp(IngestJobContext context) throws IngestModuleException { this.module.startUp(context); } - /** - * @inheritDoc - */ @Override public IngestModule.ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) { this.processingStartTime = new Date(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleProcessTerminator.java b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleProcessTerminator.java index 7f0ac84240..ad06ff65fd 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleProcessTerminator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleProcessTerminator.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"); @@ -68,9 +68,6 @@ public final class FileIngestModuleProcessTerminator implements ProcessTerminato } } - /** - * @inheritDoc - */ @Override public boolean shouldTerminateProcess() { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java index bdde998aad..5819a2f424 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -168,12 +168,9 @@ public class IngestMessage { return hash; } - //factory methods /** * Create a message of specified type * - * @param ID ID of the message, unique in the context of module - * that generated it * @param messageType message type * @param source originating module * @param subject message subject to be displayed @@ -210,8 +207,6 @@ public class IngestMessage { /** * Create error message * - * @param ID ID of the message, unique in the context of module - * that generated it * @param source originating module * @param subject message subject to be displayed * @param detailsHtml html formatted detailed message (without leading and diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleFactory.java index de99a445ab..470d728558 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleFactory.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"); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleFactoryAdapter.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleFactoryAdapter.java index 2c4831bb01..14beecd05d 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleFactoryAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleFactoryAdapter.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"); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ModuleDataEvent.java b/Core/src/org/sleuthkit/autopsy/ingest/ModuleDataEvent.java index 7c58171d59..d78169e251 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ModuleDataEvent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ModuleDataEvent.java @@ -58,7 +58,7 @@ public class ModuleDataEvent extends ChangeEvent { */ public ModuleDataEvent(String moduleName, ARTIFACT_TYPE artifactType) { super(artifactType); - this.blackboardArtifactType = new BlackboardArtifact.Type(artifactType.getTypeID(), artifactType.getLabel(), artifactType.getDisplayName()); + this.blackboardArtifactType = new BlackboardArtifact.Type(artifactType); this.moduleName = moduleName; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/events/ContentChangedEvent.java b/Core/src/org/sleuthkit/autopsy/ingest/events/ContentChangedEvent.java index 7370d90586..0f7dcdc0dc 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/events/ContentChangedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/events/ContentChangedEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,8 +45,8 @@ public final class ContentChangedEvent extends AutopsyEvent implements Serializa * Constructs a event to be published when new content is added to a case or * there is a change a recorded attribute of existing content. * - * @param contentEvent A ModuleContentEvent object containing the data - * associated with the content addition or change. + * @param eventData A ModuleContentEvent object containing the data + * associated with the content addition or change. */ public ContentChangedEvent(ModuleContentEvent eventData) { /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties index c85ead90b1..1b8dd3acc7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties @@ -43,7 +43,6 @@ FileExtMismatchSettingsPanel.mimeRemoveErrLabel.text=\ FileExtMismatchSettingsPanel.extRemoveErrLabel.text=\ FileExtMismatchSettingsPanel.mimeErrLabel.text=\ FileExtMismatchSettingsPanel.removeTypeButton.text=Remove Selected Type -FileExtMismatchSettingsPanel.saveButton.text=Save Configuration FileExtMismatchSettingsPanel.jLabel1.text=File Types: FileExtMismatchSettingsPanel.userExtTextField.text= FileExtMismatchSettingsPanel.addExtButton.text=Add Extension diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle_ja.properties index 82aa0220c3..9679198eaf 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle_ja.properties @@ -38,7 +38,6 @@ FileExtMismatchModuleSettingsPanel.skipNoExtCheckBox.text=\u62e1\u5f35\u5b50\u30 FileExtMismatchSettingsPanel.addTypeButton.text=\u30bf\u30a4\u30d7\u3092\u8ffd\u52a0 FileExtMismatchSettingsPanel.extHeaderLabel.text=\u8a31\u53ef\u3059\u308b\u62e1\u5f35\u5b50\uff1a FileExtMismatchSettingsPanel.removeTypeButton.text=\u9078\u629e\u3057\u305f\u30bf\u30a4\u30d7\u3092\u524a\u9664 -FileExtMismatchSettingsPanel.saveButton.text=\u8a2d\u5b9a\u3092\u4fdd\u5b58 FileExtMismatchSettingsPanel.jLabel1.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\uff1a FileExtMismatchSettingsPanel.addExtButton.text=\u62e1\u5f35\u5b50\u3092\u8ffd\u52a0 FileExtMismatchSettingsPanel.removeExtButton.text=\u9078\u629e\u3057\u305f\u62e1\u5f35\u5b50\u3092\u524a\u9664 diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form index 397f707b31..3b5f5d7758 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form @@ -46,13 +46,10 @@ - + - - - - + @@ -63,9 +60,7 @@ - - - + @@ -74,20 +69,6 @@
- - - - - - - - - - - - - - @@ -146,7 +127,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java index 1de79557bc..56883ef119 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java @@ -69,7 +69,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel customizeComponents(); } - @NbBundle.Messages({"FileExtMismatchSettingsPanel.Title=Global File Extension Mismatch Identification Settings"}) + @NbBundle.Messages({"FileExtMismatchSettingsPanel.Title=Global File Extension Mismatch Identification Settings"}) private void customizeComponents() { setName(Bundle.FileExtMismatchSettingsPanel_Title()); @@ -143,7 +143,6 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel jScrollPane1 = new javax.swing.JScrollPane(); jPanel1 = new javax.swing.JPanel(); - saveButton = new javax.swing.JButton(); jSplitPane1 = new javax.swing.JSplitPane(); mimePanel = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); @@ -167,15 +166,6 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel jPanel1.setPreferredSize(new java.awt.Dimension(687, 450)); - saveButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/fileextmismatch/save16.png"))); // NOI18N NON-NLS - saveButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.saveButton.text")); // NOI18N - saveButton.setEnabled(false); - saveButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - saveButtonActionPerformed(evt); - } - }); - jSplitPane1.setDividerLocation(430); jLabel1.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.jLabel1.text")); // NOI18N @@ -247,7 +237,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addComponent(removeTypeButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(mimeRemoveErrLabel) - .addContainerGap(47, Short.MAX_VALUE)) + .addContainerGap(83, Short.MAX_VALUE)) ); jSplitPane1.setLeftComponent(mimePanel); @@ -336,21 +326,17 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 667, Short.MAX_VALUE) + .addComponent(jSplitPane1) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(saveButton, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(saveMsgLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 145, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addComponent(saveMsgLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 145, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap()) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jSplitPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(saveButton) + .addComponent(jSplitPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 466, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(saveMsgLabel) .addContainerGap()) @@ -416,10 +402,6 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel setIsModified(); }//GEN-LAST:event_addExtButtonActionPerformed - private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed - store(); - }//GEN-LAST:event_saveButtonActionPerformed - private void addTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTypeButtonActionPerformed String newMime = userTypeTextField.getText(); if (newMime.isEmpty()) { @@ -555,7 +537,6 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel extErrorLabel.setText(" "); saveMsgLabel.setText(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.store.msg")); - saveButton.setEnabled(false); } else { //error JOptionPane.showMessageDialog(this, @@ -582,7 +563,6 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel } private void setIsModified() { - saveButton.setEnabled(true); saveMsgLabel.setText(" "); } @@ -592,18 +572,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel } public void ok() { - // if data is unsaved - if (saveButton.isEnabled()) { - int choice = JOptionPane.showConfirmDialog(this, - NbBundle.getMessage(this.getClass(), - "FileExtMismatchConfigPanel.ok.confDlg.msg"), - NbBundle.getMessage(this.getClass(), - "FileExtMismatchConfigPanel.confDlg.title"), - JOptionPane.YES_NO_OPTION); - if (choice == JOptionPane.YES_OPTION) { - store(); - } - } + store(); clearErrLabels(); load(); // The next time this panel is opened, we want it to be fresh } @@ -631,7 +600,6 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel private javax.swing.JTable mimeTable; private javax.swing.JButton removeExtButton; private javax.swing.JButton removeTypeButton; - private javax.swing.JButton saveButton; private javax.swing.JLabel saveMsgLabel; private javax.swing.JTextField userExtTextField; private javax.swing.JTextField userTypeTextField; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 4f7f0bd043..432b4934e0 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Objects; @@ -31,8 +32,9 @@ import org.sleuthkit.datamodel.TskCoreException; *

* Thread-safe (immutable). */ -class FileType { +class FileType implements Serializable { + private static final long serialVersionUID = 1L; private final String mimeType; private final Signature signature; private final String interestingFilesSetName; @@ -104,19 +106,20 @@ class FileType { String getFilesSetName() { return interestingFilesSetName; } - + @Override public String toString() { return this.mimeType; } - + @Override public boolean equals(Object other) { - if(other != null && other instanceof FileType) { + if (other != null && other instanceof FileType) { FileType that = (FileType) other; - if(this.getMimeType().equals(that.getMimeType()) && this.getSignature().equals(that.getSignature())) + if (this.getMimeType().equals(that.getMimeType()) && this.getSignature().equals(that.getSignature())) { return true; - } + } + } return false; } @@ -134,14 +137,16 @@ class FileType { *

* Thread-safe (immutable). */ - static class Signature { - + static class Signature implements Serializable { + + private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(Signature.class.getName()); /** * The way the signature byte sequence should be interpreted. */ enum Type { + RAW, ASCII }; @@ -156,8 +161,8 @@ class FileType { * * @param signatureBytes The signature bytes. * @param offset The offset of the signature bytes. - * @param type The type of data in the byte array. Impacts - * how it is displayed to the user in the UI. + * @param type The type of data in the byte array. Impacts how + * it is displayed to the user in the UI. */ Signature(final byte[] signatureBytes, long offset, Type type) { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); @@ -165,13 +170,13 @@ class FileType { this.type = type; this.isRelativeToStart = true; } - + /** - * Creates a file signature consisting of an ASCII string at a - * specific offset within a file. + * Creates a file signature consisting of an ASCII string at a specific + * offset within a file. * * @param signatureString The ASCII string - * @param offset The offset of the signature bytes. + * @param offset The offset of the signature bytes. */ Signature(String signatureString, long offset) { this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); @@ -179,12 +184,12 @@ class FileType { this.type = Type.ASCII; this.isRelativeToStart = true; } - + /** * Creates a file signature consisting of a sequence of bytes at a - * specific offset within a file. If bytes correspond to an ASCII - * string, use one of the other constructors so that the string is - * displayed to the user instead of the raw bytes. + * specific offset within a file. If bytes correspond to an ASCII + * string, use one of the other constructors so that the string is + * displayed to the user instead of the raw bytes. * * @param signatureBytes The signature bytes. * @param offset The offset of the signature bytes. @@ -195,16 +200,17 @@ class FileType { this.type = Type.RAW; this.isRelativeToStart = true; } - + /** * Creates a file signature consisting of a sequence of bytes at a * specific offset within a file. * - * @param signatureBytes The signature bytes. - * @param offset The offset of the signature bytes. - * @param type The type of data in the byte array. Impacts - * how it is displayed to the user in the UI. - * @param isRelativeToStart Determines whether this signature is relative to start. + * @param signatureBytes The signature bytes. + * @param offset The offset of the signature bytes. + * @param type The type of data in the byte array. Impacts + * how it is displayed to the user in the UI. + * @param isRelativeToStart Determines whether this signature is + * relative to start. */ Signature(final byte[] signatureBytes, long offset, Type type, boolean isRelativeToStart) { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); @@ -212,14 +218,15 @@ class FileType { this.type = type; this.isRelativeToStart = isRelativeToStart; } - + /** - * Creates a file signature consisting of an ASCII string at a - * specific offset within a file. + * Creates a file signature consisting of an ASCII string at a specific + * offset within a file. * - * @param signatureString The ASCII string - * @param offset The offset of the signature bytes. - * @param isRelativeToStart Determines whether this signature is relative to start. + * @param signatureString The ASCII string + * @param offset The offset of the signature bytes. + * @param isRelativeToStart Determines whether this signature is + * relative to start. */ Signature(String signatureString, long offset, boolean isRelativeToStart) { this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); @@ -227,16 +234,17 @@ class FileType { this.type = Type.ASCII; this.isRelativeToStart = isRelativeToStart; } - + /** * Creates a file signature consisting of a sequence of bytes at a - * specific offset within a file. If bytes correspond to an ASCII - * string, use one of the other constructors so that the string is - * displayed to the user instead of the raw bytes. + * specific offset within a file. If bytes correspond to an ASCII + * string, use one of the other constructors so that the string is + * displayed to the user instead of the raw bytes. * - * @param signatureBytes The signature bytes. - * @param offset The offset of the signature bytes. - * @param isRelativeToStart Determines whether this signature is relative to start. + * @param signatureBytes The signature bytes. + * @param offset The offset of the signature bytes. + * @param isRelativeToStart Determines whether this signature is + * relative to start. */ Signature(final byte[] signatureBytes, long offset, boolean isRelativeToStart) { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); @@ -271,7 +279,7 @@ class FileType { Type getType() { return type; } - + boolean isRelativeToStart() { return isRelativeToStart; } @@ -285,12 +293,13 @@ class FileType { * @return True or false. */ boolean containedIn(final AbstractFile file) { - if(offset >= file.getSize()) { + if (offset >= file.getSize()) { return false; // File is too small, offset lies outside file. } long actualOffset = offset; - if(!isRelativeToStart) + if (!isRelativeToStart) { actualOffset = file.getSize() - 1 - offset; + } if (file.getSize() < (actualOffset + signatureBytes.length)) { return false; /// too small, can't contain this signature } @@ -308,15 +317,16 @@ class FileType { return false; } } - + @Override public boolean equals(Object other) { if (other != null && other instanceof Signature) { Signature that = (Signature) other; - if(Arrays.equals(this.getSignatureBytes(), that.getSignatureBytes()) + if (Arrays.equals(this.getSignatureBytes(), that.getSignatureBytes()) && this.getOffset() == that.getOffset() - && this.getType().equals(that.getType())) + && this.getType().equals(that.getType())) { return true; + } } return false; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index e6e8269ac9..0546a01f01 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -133,48 +133,20 @@ public class FileTypeDetector { * Gets the MIME type of a file, detecting it if it is not already known. If * detection is necessary, the result is added to the case database. * - * IMPORTANT: This method should not be called except by ingest modules; all + * IMPORTANT: This method should only be called by ingest modules. All * other clients should call AbstractFile.getMIMEType, and may call * FileTypeDetector.detect, if AbstractFile.getMIMEType returns null. * * @param file The file. * - * @return A MIME type name. + * @return A MIME type name. If file type could not be detected or results + * were uncertain, octet-stream is returned. * * @throws TskCoreException if detection is required and there is a problem * writing the result to the case database. */ - @SuppressWarnings("deprecation") public String getFileType(AbstractFile file) throws TskCoreException { - String mimeType = file.getMIMEType(); - if (null != mimeType) { - return mimeType; - } - - mimeType = detect(file); - Case.getCurrentCase().getSleuthkitCase().setFileMIMEType(file, mimeType); - - /* - * Add the file type attribute to the general info artifact. Note that - * no property change is fired for this blackboard posting because - * general info artifacts are different from other artifacts, e.g., they - * are not displayed in the results tree. - * - * SPECIAL NOTE: Adding a file type attribute to the general info - * artifact is meant to be replaced by the use of the MIME type field of - * the AbstractFile class (tsk_files.mime_type in the case database). - * The attribute is still added here to support backward compatibility, - * but it introduces a check-then-act race condition that can lead to - * duplicate attributes. Various mitigation strategies were considered. - * It was decided to go with the policy that this method would not be - * called outside of ingest (see note in method docs), at least until - * such time as the attribute is no longer created. - */ - BlackboardArtifact getInfoArt = file.getGenInfoArtifact(); - BlackboardAttribute batt = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG, FileTypeIdModuleFactory.getModuleName(), mimeType); - getInfoArt.addAttribute(batt); - - return mimeType; + return detect(file, true); } /** @@ -186,9 +158,39 @@ public class FileTypeDetector { * @return A MIME type name. If file type could not be detected or results * were uncertain, octet-stream is returned. * - * @throws TskCoreException + * @throws TskCoreException If there is a problem writing the result to the + * case database. */ public String detect(AbstractFile file) throws TskCoreException { + return detect(file, false); + } + + /** + * Detects the MIME type of a file. The result is saved to the case database + * only if the add to case dastabase flag is set. + * + * @param file The file to test. + * @param addToCaseDb Whether the MIME type should be added to the case + * database. This flag is part of a partial workaround + * for a check-then-act-race condition (see notes in + * comments for details). + * + * @return A MIME type name. If file type could not be detected or results + * were uncertain, octet-stream is returned. + * + * @throws TskCoreException If there is a problem writing the result to the + * case database. + */ + private String detect(AbstractFile file, boolean addToCaseDb) throws TskCoreException { + /* + * Check to see if the file has already been typed. This is the "check" + * part of a check-then-act race condition (see note below). + */ + String mimeType = file.getMIMEType(); + if (null != mimeType) { + return mimeType; + } + /* * Mark non-regular files (refer to TskData.TSK_FS_META_TYPE_ENUM), * zero-sized files, unallocated space, and unused blocks (refer to @@ -198,18 +200,21 @@ public class FileTypeDetector { || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR)) { - return MimeTypes.OCTET_STREAM; + mimeType = MimeTypes.OCTET_STREAM; } /* - * Give precedence to user-defined types. + * If the file is a regular file, give precedence to user-defined types. + */ + if (null == mimeType) { + mimeType = detectUserDefinedType(file, addToCaseDb); + } + + /* + * If the file does not match a user-defined type, send the initial + * bytes to Tika. */ - String mimeType = detectUserDefinedType(file); if (null == mimeType) { - /* - * The file does not match a user-defined type. Send the initial - * bytes to Tika. - */ try { byte buf[]; int len = file.read(buffer, 0, BUFFER_SIZE); @@ -237,25 +242,63 @@ public class FileTypeDetector { mimeType = MimeTypes.OCTET_STREAM; } } + + /* + * If adding the result to the case database, do so now. + * + * NOTE: This condtional is a way to deal with the check-then-act race + * condition created by the gap between querying the MIME type and + * recording it. It is not really a problem for the mime_type column of + * the tsk_files table, but it can lead to duplicate blackboard posts, + * and the posts are required to maintain backward compatibility. + * Various mitigation strategies were considered. It was decided to go + * with the policy that only ingest modules are allowed to add file + * types to the case database, at least until such time as file types + * are no longer posted to the blackboard. Of course, this is not a + * perfect solution. It's not really enforceable for community + * contributed plug ins and it does not handle the unlikely but possible + * scenario of multiple processes typing the same file for a multi-user + * case. + */ + if (addToCaseDb) { + /* + * Add the MIME type to the files table in the case database. + */ + Case.getCurrentCase().getSleuthkitCase().setFileMIMEType(file, mimeType); + + /* + * Post to the blackboard, adding the file type attribute to the + * general info artifact. A property change is not fired for this + * posting because general info artifacts are different from other + * artifacts, e.g., they are not displayed in the results tree. + */ + BlackboardArtifact getInfoArt = file.getGenInfoArtifact(); + @SuppressWarnings("deprecation") + BlackboardAttribute batt = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG, FileTypeIdModuleFactory.getModuleName(), mimeType); + getInfoArt.addAttribute(batt); + } + return mimeType; } /** * Determines whether or not the a file matches a user-defined or Autopsy - * predefined file type. If a match is found and the file type definition - * calls for an alert on a match, an interesting file hit artifact is posted - * to the blackboard. + * predefined file type. If postToBlackBoard is true, and a match is found, + * and the file type definition calls for an alert on a match, an + * interesting file hit artifact is posted to the blackboard. * - * @param file The file to test. + * @param file The file to test. + * @param postToBlackBoard Whether an interesting file hit could be posted + * to the blackboard. * * @return The file type name string or null, if no match is detected. * * @throws TskCoreException */ - private String detectUserDefinedType(AbstractFile file) throws TskCoreException { + private String detectUserDefinedType(AbstractFile file, boolean postToBlackBoard) throws TskCoreException { for (FileType fileType : userDefinedFileTypes) { if (fileType.matches(file)) { - if (fileType.alertOnMatch()) { + if (postToBlackBoard && fileType.alertOnMatch()) { /* * Create an interesting file hit artifact. */ diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 8f2dbaabca..6ae8404c13 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -19,7 +19,9 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.file.Path; @@ -27,6 +29,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; +import javax.persistence.PersistenceException; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -34,10 +37,13 @@ import org.w3c.dom.NodeList; import javax.xml.bind.DatatypeConverter; import javax.xml.transform.TransformerException; import org.openide.util.NbBundle; +import org.openide.util.io.NbObjectInputStream; +import org.openide.util.io.NbObjectOutputStream; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; +import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Node; import org.xml.sax.SAXException; @@ -59,7 +65,8 @@ import org.xml.sax.SAXException; final class UserDefinedFileTypesManager { private static final Logger logger = Logger.getLogger(UserDefinedFileTypesManager.class.getName()); - private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS + private static final String USER_DEFINED_TYPES_XML_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS + private static final String USER_DEFINED_TYPES_SERIALIZATION_FILE = "UserFileTypeDefinitions.settings"; private static final String FILE_TYPES_TAG_NAME = "FileTypes"; //NON-NLS private static final String FILE_TYPE_TAG_NAME = "FileType"; //NON-NLS private static final String MIME_TYPE_TAG_NAME = "MimeType"; //NON-NLS @@ -246,12 +253,19 @@ final class UserDefinedFileTypesManager { */ private void loadUserDefinedFileTypes() throws UserDefinedFileTypesException { try { - String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPE_DEFINITIONS_FILE); - File file = new File(filePath); - if (file.exists() && file.canRead()) { - for (FileType fileType : XmlReader.readFileTypes(filePath)) { + File serialized = new File(getFileTypeDefinitionsFilePath(USER_DEFINED_TYPES_SERIALIZATION_FILE)); + if (serialized.exists()) { + for (FileType fileType : readFileTypesSerialized()) { addUserDefinedFileType(fileType); } + } else { + String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPES_XML_FILE); + File xmlFile = new File(filePath); + if (xmlFile.exists()) { + for (FileType fileType : XMLDefinitionsReader.readFileTypes(filePath)) { + addUserDefinedFileType(fileType); + } + } } } catch (IOException | ParserConfigurationException | SAXException ex) { @@ -282,14 +296,8 @@ final class UserDefinedFileTypesManager { * types. */ synchronized void setUserDefinedFileTypes(List newFileTypes) throws UserDefinedFileTypesException { - try { - String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPE_DEFINITIONS_FILE); - XmlWriter.writeFileTypes(newFileTypes, filePath); - } catch (ParserConfigurationException | FileNotFoundException | UnsupportedEncodingException | TransformerException ex) { - throwUserDefinedFileTypesException(ex, "UserDefinedFileTypesManager.saveFileTypes.errorMessage"); - } catch (IOException ex) { - throwUserDefinedFileTypesException(ex, "UserDefinedFileTypesManager.saveFileTypes.errorMessage"); - } + String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPES_SERIALIZATION_FILE); + writeFileTypes(newFileTypes, filePath); } /** @@ -305,127 +313,52 @@ final class UserDefinedFileTypesManager { } /** - * Provides a mechanism for writing a set of file type definitions to an XML - * file. + * Writes a set of file types to a file. + * + * @param fileTypes A collection of file types. + * @param filePath The path to the destination file. + * + * @throws ParserConfigurationException + * @throws IOException + * @throws FileNotFoundException + * @throws UnsupportedEncodingException + * @throws TransformerException */ - private static class XmlWriter { + private static void writeFileTypes(List fileTypes, String filePath) throws UserDefinedFileTypesException { + try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(filePath))) { + UserDefinedFileTypesSettings settings = new UserDefinedFileTypesSettings(fileTypes); + out.writeObject(settings); + } catch (IOException ex) { + throw new UserDefinedFileTypesException(String.format("Failed to write settings to %s", filePath), ex); + } + } - /** - * Writes a set of file type definitions to an XML file. - * - * @param fileTypes A collection of file types. - * @param filePath The path to the destination file. - * - * @throws ParserConfigurationException - * @throws IOException - * @throws FileNotFoundException - * @throws UnsupportedEncodingException - * @throws TransformerException - */ - private static void writeFileTypes(List fileTypes, String filePath) throws ParserConfigurationException, IOException, FileNotFoundException, UnsupportedEncodingException, TransformerException { - Document doc = XMLUtil.createDocument(); - Element fileTypesElem = doc.createElement(FILE_TYPES_TAG_NAME); - doc.appendChild(fileTypesElem); - for (FileType fileType : fileTypes) { - Element fileTypeElem = XmlWriter.createFileTypeElement(fileType, doc); - fileTypesElem.appendChild(fileTypeElem); + /** + * Reads the file types + * + * @param filePath the file path where the file types are to be read + * + * @return the file types + * + * @throws ParserConfigurationException If the file cannot be read + */ + private static List readFileTypesSerialized() throws UserDefinedFileTypesException { + File serializedDefs = new File(getFileTypeDefinitionsFilePath(USER_DEFINED_TYPES_SERIALIZATION_FILE)); + try { + try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(serializedDefs))) { + UserDefinedFileTypesSettings filesSetsSettings = (UserDefinedFileTypesSettings) in.readObject(); + return filesSetsSettings.getUserDefinedFileTypes(); } - XMLUtil.saveDocument(doc, ENCODING_FOR_XML_FILE, filePath); + } catch (IOException | ClassNotFoundException ex) { + throw new UserDefinedFileTypesException("Couldn't read serialized settings.", ex); } - - /** - * Creates an XML representation of a file type. - * - * @param fileType The file type object. - * @param doc The WC3 DOM object to use to create the XML. - * - * @return An XML element. - */ - private static Element createFileTypeElement(FileType fileType, Document doc) { - Element fileTypeElem = doc.createElement(FILE_TYPE_TAG_NAME); - XmlWriter.addMimeTypeElement(fileType, fileTypeElem, doc); - XmlWriter.addSignatureElement(fileType, fileTypeElem, doc); - XmlWriter.addInterestingFilesSetElement(fileType, fileTypeElem, doc); - XmlWriter.addAlertAttribute(fileType, fileTypeElem); - return fileTypeElem; - } - - /** - * Add a MIME type child element to a file type XML element. - * - * @param fileType The file type to use as a content source. - * @param fileTypeElem The parent file type element. - * @param doc The WC3 DOM object to use to create the XML. - */ - private static void addMimeTypeElement(FileType fileType, Element fileTypeElem, Document doc) { - Element typeNameElem = doc.createElement(MIME_TYPE_TAG_NAME); - typeNameElem.setTextContent(fileType.getMimeType()); - fileTypeElem.appendChild(typeNameElem); - } - - /** - * Add a signature child element to a file type XML element. - * - * @param fileType The file type to use as a content source. - * @param fileTypeElem The parent file type element. - * @param doc The WC3 DOM object to use to create the XML. - */ - private static void addSignatureElement(FileType fileType, Element fileTypeElem, Document doc) { - Signature signature = fileType.getSignature(); - Element signatureElem = doc.createElement(SIGNATURE_TAG_NAME); - - Element bytesElem = doc.createElement(BYTES_TAG_NAME); - bytesElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); - signatureElem.appendChild(bytesElem); - - Element offsetElem = doc.createElement(OFFSET_TAG_NAME); - offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); - offsetElem.setAttribute(RELATIVE_ATTRIBUTE, String.valueOf(signature.isRelativeToStart())); - signatureElem.appendChild(offsetElem); - - signatureElem.setAttribute(SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); - fileTypeElem.appendChild(signatureElem); - } - - /** - * Add an interesting files set element to a file type XML element. - * - * @param fileType The file type to use as a content source. - * @param fileTypeElem The parent file type element. - * @param doc The WC3 DOM object to use to create the XML. - */ - private static void addInterestingFilesSetElement(FileType fileType, Element fileTypeElem, Document doc) { - if (!fileType.getFilesSetName().isEmpty()) { - Element filesSetElem = doc.createElement(INTERESTING_FILES_SET_TAG_NAME); - filesSetElem.setTextContent(fileType.getFilesSetName()); - fileTypeElem.appendChild(filesSetElem); - } - } - - /** - * Add an alert attribute to a file type XML element. - * - * @param fileType The file type to use as a content source. - * @param fileTypeElem The parent file type element. - */ - private static void addAlertAttribute(FileType fileType, Element fileTypeElem) { - fileTypeElem.setAttribute(ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); - } - - /** - * Private constructor suppresses creation of instanmces of this utility - * class. - */ - private XmlWriter() { - } - } /** * Provides a mechanism for reading a set of file type definitions from an * XML file. */ - private static class XmlReader { + private static class XMLDefinitionsReader { /** * Reads a set of file type definitions from an XML file. @@ -434,7 +367,7 @@ final class UserDefinedFileTypesManager { * * @return A collection of file types read from the XML file. */ - private static List readFileTypes(String filePath) throws IOException, ParserConfigurationException, SAXException { + private static List readFileTypes(String filePath) throws IOException, SAXException, ParserConfigurationException { List fileTypes = new ArrayList<>(); /* * RC: Commenting out the loadDocument overload that validates @@ -453,7 +386,7 @@ final class UserDefinedFileTypesManager { NodeList fileTypeElems = fileTypesElem.getElementsByTagName(FILE_TYPE_TAG_NAME); for (int i = 0; i < fileTypeElems.getLength(); ++i) { Element fileTypeElem = (Element) fileTypeElems.item(i); - FileType fileType = XmlReader.parseFileType(fileTypeElem); + FileType fileType = XMLDefinitionsReader.parseFileType(fileTypeElem); fileTypes.add(fileType); } } @@ -472,10 +405,10 @@ final class UserDefinedFileTypesManager { * @throws NumberFormatException */ private static FileType parseFileType(Element fileTypeElem) throws IllegalArgumentException, NumberFormatException { - String mimeType = XmlReader.parseMimeType(fileTypeElem); - Signature signature = XmlReader.parseSignature(fileTypeElem); - String filesSetName = XmlReader.parseInterestingFilesSet(fileTypeElem); - boolean alert = XmlReader.parseAlert(fileTypeElem); + String mimeType = XMLDefinitionsReader.parseMimeType(fileTypeElem); + Signature signature = XMLDefinitionsReader.parseSignature(fileTypeElem); + String filesSetName = XMLDefinitionsReader.parseInterestingFilesSet(fileTypeElem); + boolean alert = XMLDefinitionsReader.parseAlert(fileTypeElem); return new FileType(mimeType, signature, filesSetName, alert); } @@ -573,7 +506,7 @@ final class UserDefinedFileTypesManager { * Private constructor suppresses creation of instanmces of this utility * class. */ - private XmlReader() { + private XMLDefinitionsReader() { } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesSettings.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesSettings.java new file mode 100755 index 0000000000..1b69d1dcc4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesSettings.java @@ -0,0 +1,45 @@ +/* + * 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 java.io.Serializable; +import java.util.List; + +/** + * Settings object for user defined file types + */ +class UserDefinedFileTypesSettings implements Serializable { + + private static final long serialVersionUID = 1L; + private List userDefinedFileTypes; + + UserDefinedFileTypesSettings(List userDefinedFileTypes) { + this.userDefinedFileTypes = userDefinedFileTypes; + } + + /** + * Gets the list of file types contained within the settings + * + * @return the userDefinedFileTypes + */ + public List getUserDefinedFileTypes() { + return userDefinedFileTypes; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties index d535c310f4..0be3a1924f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties @@ -14,8 +14,8 @@ ArtifactSelectionDialog.selectAllButton.text=Select All ReportGenerationPanel.closeButton.text=Close ReportProgressPanel.reportLabel.text=reportLabel ReportProgressPanel.pathLabel.text=pathLabel -ReportProgressPanel.separationLabel.text=- -ReportProgressPanel.processingLabel.text=processingLabel +ReportProgressPanel.separationLabel.text=: +ReportProgressPanel.statusMessageLabel.text=processingLabel ReportGenerationPanel.titleLabel.text=Report Generation Progress ReportVisualPanel2.taggedResultsRadioButton.text=Tagged Results ReportVisualPanel2.allResultsRadioButton.text=All Results diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties index bc76fbb82f..6ff657b68a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties @@ -1,247 +1,246 @@ -OpenIDE-Module-Name=\u30EC\u30DD\u30FC\u30C8 -CTL_ReportWizardAction=\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C -ArtifactSelectionDialog.titleLabel.text=\u3069\u306E\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u306B\u3064\u3044\u3066\u30EC\u30DD\u30FC\u30C8\u3059\u308B\u304B\u9078\u629E\u3057\u3066\u4E0B\u3055\u3044\uFF1A +OpenIDE-Module-Name=\u30ec\u30dd\u30fc\u30c8 +CTL_ReportWizardAction=\u30ec\u30dd\u30fc\u30c8\u3092\u5b9f\u884c +ArtifactSelectionDialog.titleLabel.text=\u3069\u306e\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u306b\u3064\u3044\u3066\u30ec\u30dd\u30fc\u30c8\u3059\u308b\u304b\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044\uff1a ArtifactSelectionDialog.okButton.text=OK -ReportVisualPanel1.reportModulesLabel.text=\u30EC\u30DD\u30FC\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\uFF1A -DefaultReportConfigurationPanel.infoLabel.text=\u3053\u306E\u30EC\u30DD\u30FC\u30C8\u306F\u6B21\u306E\u30B9\u30AF\u30EA\u30FC\u30F3\u3067\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002 -ReportVisualPanel2.dataLabel.text=\u3069\u306E\u30C7\u30FC\u30BF\u306B\u3064\u3044\u3066\u30EC\u30DD\u30FC\u30C8\u3059\u308B\u304B\u9078\u629E\u3057\u3066\u4E0B\u3055\u3044\uFF1A -ReportVisualPanel2.deselectAllButton.text=\u5168\u3066\u9078\u629E\u89E3\u9664 -ReportVisualPanel2.selectAllButton.text=\u5168\u3066\u9078\u629E -ReportVisualPanel2.advancedButton.text=\u30C7\u30FC\u30BF\u30BF\u30A4\u30D7 -ArtifactSelectionDialog.deselectAllButton.text=\u5168\u3066\u9078\u629E\u89E3\u9664 -ArtifactSelectionDialog.selectAllButton.text=\u5168\u3066\u9078\u629E -ReportGenerationPanel.closeButton.text=\u9589\u3058\u308B -ReportProgressPanel.reportLabel.text=\u30EC\u30DD\u30FC\u30C8\u30E9\u30D9\u30EB -ReportProgressPanel.pathLabel.text=\u30D1\u30B9\u30E9\u30D9\u30EB -ReportProgressPanel.separationLabel.text=- -ReportProgressPanel.processingLabel.text=\u30D7\u30ED\u30BB\u30B7\u30F3\u30B0\u30E9\u30D9\u30EB -ReportGenerationPanel.titleLabel.text=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u30D7\u30ED\u30B0\u30EC\u30B9 -ReportVisualPanel2.taggedResultsRadioButton.text=\u30BF\u30B0\u3055\u308C\u305F\u7D50\u679C -ReportVisualPanel2.allResultsRadioButton.text=\u5168\u3066\u306E\u7D50\u679C -ReportWizardFileOptionsVisualPanel.selectAllButton.text=\u5168\u3066\u9078\u629E -ReportWizardFileOptionsVisualPanel.deselectAllButton.text=\u5168\u3066\u9078\u629E\u89E3\u9664 -ReportWizardFileOptionsVisualPanel.jLabel1.text=\u30D5\u30A1\u30A4\u30EB\u30EC\u30DD\u30FC\u30C8\u306B\u542B\u3081\u308B\u30A2\u30A4\u30C6\u30E0\u3092\u9078\u629E\u3057\u3066\u4E0B\u3055\u3044\uFF1A -ArtifactSelectionDialog.dlgTitle.text=\u30A2\u30C9\u30D0\u30F3\u30B9\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u9078\u629E -FileReportDataTypes.filename.text=\u540D\u524D -FileReportDataTypes.fileExt.text=\u30D5\u30A1\u30A4\u30EB\u62E1\u5F35\u5B50 -FileReportDataTypes.fileType.text=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7 -FileReportDataTypes.isDel.text=\u306F\u524A\u9664\u3055\u308C\u307E\u3057\u305F -FileReportDataTypes.aTime.text=\u6700\u5F8C\u306E\u30A2\u30AF\u30BB\u30B9 -FileReportDataTypes.crTime.text=\u4F5C\u6210\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB -FileReportDataTypes.mTime.text=\u6700\u5F8C\u306E\u4FEE\u6B63 -FileReportDataTypes.size.text=\u30B5\u30A4\u30BA -FileReportDataTypes.address.text=\u30A2\u30C9\u30EC\u30B9 -FileReportDataTypes.hash.text=\u30CF\u30C3\u30B7\u30E5\u5024 -FileReportDataTypes.knownStatus.text=\u65E2\u77E5\u30B9\u30C6\u30FC\u30BF\u30B9 -FileReportDataTypes.perms.text=\u30D1\u30FC\u30DF\u30C3\u30B7\u30E7\u30F3 -FileReportDataTypes.path.text=\u30D5\u30EB\u30D1\u30B9 -FileReportText.getName.text=\u30D5\u30A1\u30A4\u30EB - \u30C6\u30AD\u30B9\u30C8 -FileReportText.getDesc.text=\u30B1\u30FC\u30B9\u306E\u500B\u5225\u30D5\u30A1\u30A4\u30EB\u306B\u3064\u3044\u3066\u306E\u60C5\u5831\u3092\u6301\u3064\u3001\u30BF\u30D6\u533A\u5207\u308A\u30C6\u30AD\u30B9\u30C8\u30D5\u30A1\u30A4\u30EB\u3002 -ReportBodyFile.progress.querying=\u30D5\u30A1\u30A4\u30EB\u306E\u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u4E2D\u2026 -ReportBodyFile.ingestWarning.text=\u8B66\u544A\u3001\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B5\u30FC\u30D3\u30B9\u304C\u5B8C\u4E86\u3059\u308B\u524D\u306B\u30EC\u30DD\u30FC\u30C8\u304C\u5B9F\u884C\u3055\u308C\u307E\u3057\u305F\uFF01 -ReportBodyFile.progress.loading=\u30D5\u30A1\u30A4\u30EB\u306E\u8AAD\u307F\u8FBC\u307F\u4E2D\u2026 -ReportBodyFile.progress.processing={0}\u3092\u51E6\u7406\u4E2D\u2026 -ReportBodyFile.getName.text=TSK\u30DC\u30C7\u30A3\u30D5\u30A1\u30A4\u30EB -ReportBodyFile.getDesc.text=\u5404\u30D5\u30A1\u30A4\u30EB\u306EMAC\u30BF\u30A4\u30E0\u3092\u542B\u3080\u3001\u30DC\u30C7\u30A3\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u30EC\u30DD\u30FC\u30C8\u3002\u30BF\u30A4\u30E0\u30E9\u30A4\u30F3\u30D3\u30E5\u30FC\u306B\u3053\u306E\u5F62\u5F0F\u3092\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002 +ReportVisualPanel1.reportModulesLabel.text=\u30ec\u30dd\u30fc\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\uff1a +DefaultReportConfigurationPanel.infoLabel.text=\u3053\u306e\u30ec\u30dd\u30fc\u30c8\u306f\u6b21\u306e\u30b9\u30af\u30ea\u30fc\u30f3\u3067\u8a2d\u5b9a\u3055\u308c\u307e\u3059\u3002 +ReportVisualPanel2.dataLabel.text=\u3069\u306e\u30c7\u30fc\u30bf\u306b\u3064\u3044\u3066\u30ec\u30dd\u30fc\u30c8\u3059\u308b\u304b\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044\uff1a +ReportVisualPanel2.deselectAllButton.text=\u5168\u3066\u9078\u629e\u89e3\u9664 +ReportVisualPanel2.selectAllButton.text=\u5168\u3066\u9078\u629e +ReportVisualPanel2.advancedButton.text=\u30c7\u30fc\u30bf\u30bf\u30a4\u30d7 +ArtifactSelectionDialog.deselectAllButton.text=\u5168\u3066\u9078\u629e\u89e3\u9664 +ArtifactSelectionDialog.selectAllButton.text=\u5168\u3066\u9078\u629e +ReportGenerationPanel.closeButton.text=\u9589\u3058\u308b +ReportProgressPanel.reportLabel.text=\u30ec\u30dd\u30fc\u30c8\u30e9\u30d9\u30eb +ReportProgressPanel.pathLabel.text=\u30d1\u30b9\u30e9\u30d9\u30eb +ReportProgressPanel.separationLabel.text=: +ReportProgressPanel.statusMessageLabel.text=\u30d7\u30ed\u30bb\u30b7\u30f3\u30b0\u30e9\u30d9\u30eb +ReportGenerationPanel.titleLabel.text=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u30d7\u30ed\u30b0\u30ec\u30b9 +ReportVisualPanel2.taggedResultsRadioButton.text=\u30bf\u30b0\u3055\u308c\u305f\u7d50\u679c +ReportVisualPanel2.allResultsRadioButton.text=\u5168\u3066\u306e\u7d50\u679c +ReportWizardFileOptionsVisualPanel.selectAllButton.text=\u5168\u3066\u9078\u629e +ReportWizardFileOptionsVisualPanel.deselectAllButton.text=\u5168\u3066\u9078\u629e\u89e3\u9664 +ReportWizardFileOptionsVisualPanel.jLabel1.text=\u30d5\u30a1\u30a4\u30eb\u30ec\u30dd\u30fc\u30c8\u306b\u542b\u3081\u308b\u30a2\u30a4\u30c6\u30e0\u3092\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044\uff1a +ArtifactSelectionDialog.dlgTitle.text=\u30a2\u30c9\u30d0\u30f3\u30b9\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u9078\u629e +FileReportDataTypes.filename.text=\u540d\u524d +FileReportDataTypes.fileExt.text=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50 +FileReportDataTypes.fileType.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7 +FileReportDataTypes.isDel.text=\u306f\u524a\u9664\u3055\u308c\u307e\u3057\u305f +FileReportDataTypes.aTime.text=\u6700\u5f8c\u306e\u30a2\u30af\u30bb\u30b9 +FileReportDataTypes.crTime.text=\u4f5c\u6210\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb +FileReportDataTypes.mTime.text=\u6700\u5f8c\u306e\u4fee\u6b63 +FileReportDataTypes.size.text=\u30b5\u30a4\u30ba +FileReportDataTypes.address.text=\u30a2\u30c9\u30ec\u30b9 +FileReportDataTypes.hash.text=\u30cf\u30c3\u30b7\u30e5\u5024 +FileReportDataTypes.knownStatus.text=\u65e2\u77e5\u30b9\u30c6\u30fc\u30bf\u30b9 +FileReportDataTypes.perms.text=\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3 +FileReportDataTypes.path.text=\u30d5\u30eb\u30d1\u30b9 +FileReportText.getName.text=\u30d5\u30a1\u30a4\u30eb - \u30c6\u30ad\u30b9\u30c8 +FileReportText.getDesc.text=\u30b1\u30fc\u30b9\u306e\u500b\u5225\u30d5\u30a1\u30a4\u30eb\u306b\u3064\u3044\u3066\u306e\u60c5\u5831\u3092\u6301\u3064\u3001\u30bf\u30d6\u533a\u5207\u308a\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30a4\u30eb\u3002 +ReportBodyFile.progress.querying=\u30d5\u30a1\u30a4\u30eb\u306e\u30af\u30a8\u30ea\u3092\u5b9f\u884c\u4e2d\u2026 +ReportBodyFile.ingestWarning.text=\u8b66\u544a\u3001\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b5\u30fc\u30d3\u30b9\u304c\u5b8c\u4e86\u3059\u308b\u524d\u306b\u30ec\u30dd\u30fc\u30c8\u304c\u5b9f\u884c\u3055\u308c\u307e\u3057\u305f\uff01 +ReportBodyFile.progress.loading=\u30d5\u30a1\u30a4\u30eb\u306e\u8aad\u307f\u8fbc\u307f\u4e2d\u2026 +ReportBodyFile.progress.processing={0}\u3092\u51e6\u7406\u4e2d\u2026 +ReportBodyFile.getName.text=TSK\u30dc\u30c7\u30a3\u30d5\u30a1\u30a4\u30eb +ReportBodyFile.getDesc.text=\u5404\u30d5\u30a1\u30a4\u30eb\u306eMAC\u30bf\u30a4\u30e0\u3092\u542b\u3080\u3001\u30dc\u30c7\u30a3\u30d5\u30a1\u30a4\u30eb\u5f62\u5f0f\u30ec\u30dd\u30fc\u30c8\u3002\u30bf\u30a4\u30e0\u30e9\u30a4\u30f3\u30d3\u30e5\u30fc\u306b\u3053\u306e\u5f62\u5f0f\u3092\u4f7f\u7528\u3067\u304d\u307e\u3059\u3002 ReportBodyFile.getFilePath.text=BodyFile.txt -ReportBranding.defaultReportTitle.text=Autopsy\u30D5\u30A9\u30EC\u30F3\u30B8\u30C3\u30AF\u30EC\u30DD\u30FC\u30C8 -ReportBranding.defaultReportFooter.text=Autopsy\u30AA\u30FC\u30D7\u30F3\u30BD\u30FC\u30B9\u30FB\u30C7\u30B8\u30BF\u30EB\u30FB\u30D5\u30A9\u30EC\u30F3\u30B8\u30C3\u30AF\u30FB\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0\u306B\u3088\u308A\u63D0\u4F9B - www.sleuthkit.org -ReportExcel.numAartifacts.text=\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u6570\uFF1A -ReportExcel.getName.text=\u7D50\u679C - Excel -ReportExcel.getDesc.text=\u7D50\u679C\u306B\u95A2\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u3002Excel(XLS)\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u3067\u30A2\u30A4\u30C6\u30E0\u306E\u30BF\u30B0\u4ED8\u3051\u304C\u3055\u308C\u3066\u3044\u307E\u3059\u3002 -ReportExcel.sheetName.text=\u30B5\u30DE\u30EA\u30FC -ReportExcel.cellVal.summary=\u30B5\u30DE\u30EA\u30FC -ReportExcel.cellVal.caseName=\u30B1\u30FC\u30B9\u540D\uFF1A -ReportExcel.cellVal.caseNum=\u30B1\u30FC\u30B9\u756A\u53F7\uFF1A -ReportExcel.cellVal.examiner=\u8ABF\u67FB\u62C5\u5F53\u8005\uFF1A -ReportExcel.cellVal.numImages=\u30A4\u30E1\u30FC\u30B8\u6570\uFF1A -ReportGenerationPanel.confDlg.sureToClose.msg=\u3053\u306E\u30C0\u30A4\u30A2\u30ED\u30B0\u3092\u672C\u5F53\u306B\u9589\u3058\u307E\u3059\u304B\uFF1F\n\u5168\u3066\u306E\u30EC\u30DD\u30FC\u30C8\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3059\u3002 -ReportGenerationPanel.confDlg.title.closing=\u9589\u3058\u3066\u3044\u307E\u3059 -ReportGenerator.displayProgress.title.text=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u30D7\u30ED\u30B0\u30EC\u30B9\u2026 -ReportGenerator.progress.queryingDb.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u4E2D\u2026 -ReportGenerator.progress.processingFile.text={0}\u3092\u51E6\u7406\u4E2D -ReportGenerator.artifactTable.taggedResults.text=\u6B21\u306E\u4E2D\u306E\u4E00\u3064\u3067\u30BF\u30B0\u3055\u308C\u305F\u7D50\u679C\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\uFF1A -ReportGenerator.progress.processing={0}\u3092\u51E6\u7406\u4E2D\u2026 -ReportGenerator.msgShow.skippingArtType.title=\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u30BF\u30A4\u30D7{0}\u3092\u30EC\u30DD\u30FC\u30C8\u3067\u30B9\u30AD\u30C3\u30D7\u3057\u3066\u3044\u307E\u3059 -ReportGenerator.msgShow.skippingArtType.msg=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u3059\u308B\u306E\u306B\u4E0D\u660E\u306A\u30B3\u30E9\u30E0 -ReportGenerator.msgShow.skippingArtRow.title=\u30BF\u30A4\u30D7{0}\u306E\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u884C\u3092\u30EC\u30DD\u30FC\u30C8\u3067\u30B9\u30AD\u30C3\u30D7\u3057\u3066\u3044\u307E\u3059 -ReportGenerator.msgShow.skippingArtRow.msg=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u3059\u308B\u306E\u306B\u4E0D\u660E\u306A\u30B3\u30E9\u30E0 -ReportGenerator.makeContTagTab.taggedFiles.msg=\u306E\u4E2D\u306E\u4E00\u3064\u3067\u30BF\u30B0\u3055\u308C\u305F\u7D50\u679C\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\uFF1A -ReportGenerator.makeBbArtTagTab.taggedRes.msg=\u3053\u306E\u30EC\u30DD\u30FC\u30C8\u306B\u306F\u6B21\u3067\u30BF\u30B0\u3055\u308C\u305F\u7D50\u679C\u3057\u304B\u542B\u307E\u308C\u307E\u305B\u3093\uFF1A -ReportGenerator.tagTable.header.resultType=\u7D50\u679C\u30BF\u30A4\u30D7 -ReportGenerator.tagTable.header.tag=\u30BF\u30B0 -ReportGenerator.tagTable.header.comment=\u30B3\u30E1\u30F3\u30C8 -ReportGenerator.tagTable.header.srcFile=\u30BD\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB -ReportGenerator.progress.createdThumb.text=\u30B5\u30E0\u30CD\u30A4\u30EB\u3092\u4F5C\u6210\u4E2D\u2026 -ReportGenerator.thumbnailTable.name=\u30B5\u30E0\u30CD\u30A4\u30EB -ReportGenerator.thumbnailTable.desc=\u30BF\u30B0\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB\u3084\u7D50\u679C\u306B\u95A2\u9023\u3059\u308B\u30A4\u30E1\u30FC\u30B8\u306E\u30B5\u30E0\u30CD\u30A4\u30EB\u304C\u542B\u307E\u308C\u307E\u3059\u3002 -ReportGenerator.writeKwHits.userSrchs=\u30E6\u30FC\u30B6\u691C\u7D22 -ReportGenerator.progress.processingList={0} ({1})\u3092\u51E6\u7406\u4E2D\u2026 +ReportBranding.defaultReportTitle.text=Autopsy\u30d5\u30a9\u30ec\u30f3\u30b8\u30c3\u30af\u30ec\u30dd\u30fc\u30c8 +ReportBranding.defaultReportFooter.text=Autopsy\u30aa\u30fc\u30d7\u30f3\u30bd\u30fc\u30b9\u30fb\u30c7\u30b8\u30bf\u30eb\u30fb\u30d5\u30a9\u30ec\u30f3\u30b8\u30c3\u30af\u30fb\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u306b\u3088\u308a\u63d0\u4f9b - www.sleuthkit.org +ReportExcel.numAartifacts.text=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u6570\uff1a +ReportExcel.getName.text=\u7d50\u679c - Excel +ReportExcel.getDesc.text=\u7d50\u679c\u306b\u95a2\u3059\u308b\u30ec\u30dd\u30fc\u30c8\u3002Excel(XLS)\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3067\u30a2\u30a4\u30c6\u30e0\u306e\u30bf\u30b0\u4ed8\u3051\u304c\u3055\u308c\u3066\u3044\u307e\u3059\u3002 +ReportExcel.sheetName.text=\u30b5\u30de\u30ea\u30fc +ReportExcel.cellVal.summary=\u30b5\u30de\u30ea\u30fc +ReportExcel.cellVal.caseName=\u30b1\u30fc\u30b9\u540d\uff1a +ReportExcel.cellVal.caseNum=\u30b1\u30fc\u30b9\u756a\u53f7\uff1a +ReportExcel.cellVal.examiner=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a +ReportExcel.cellVal.numImages=\u30a4\u30e1\u30fc\u30b8\u6570\uff1a +ReportGenerationPanel.confDlg.sureToClose.msg=\u3053\u306e\u30c0\u30a4\u30a2\u30ed\u30b0\u3092\u672c\u5f53\u306b\u9589\u3058\u307e\u3059\u304b\uff1f\n\u5168\u3066\u306e\u30ec\u30dd\u30fc\u30c8\u304c\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3059\u3002 +ReportGenerationPanel.confDlg.title.closing=\u9589\u3058\u3066\u3044\u307e\u3059 +ReportGenerator.displayProgress.title.text=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u30d7\u30ed\u30b0\u30ec\u30b9\u2026 +ReportGenerator.progress.queryingDb.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30af\u30a8\u30ea\u3092\u5b9f\u884c\u4e2d\u2026 +ReportGenerator.progress.processingFile.text={0}\u3092\u51e6\u7406\u4e2d +ReportGenerator.artifactTable.taggedResults.text=\u6b21\u306e\u4e2d\u306e\u4e00\u3064\u3067\u30bf\u30b0\u3055\u308c\u305f\u7d50\u679c\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059\uff1a +ReportGenerator.progress.processing={0}\u3092\u51e6\u7406\u4e2d\u2026 +ReportGenerator.msgShow.skippingArtType.title=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30bf\u30a4\u30d7{0}\u3092\u30ec\u30dd\u30fc\u30c8\u3067\u30b9\u30ad\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059 +ReportGenerator.msgShow.skippingArtType.msg=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u3059\u308b\u306e\u306b\u4e0d\u660e\u306a\u30b3\u30e9\u30e0 +ReportGenerator.msgShow.skippingArtRow.title=\u30bf\u30a4\u30d7{0}\u306e\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u884c\u3092\u30ec\u30dd\u30fc\u30c8\u3067\u30b9\u30ad\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059 +ReportGenerator.msgShow.skippingArtRow.msg=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u3059\u308b\u306e\u306b\u4e0d\u660e\u306a\u30b3\u30e9\u30e0 +ReportGenerator.makeContTagTab.taggedFiles.msg=\u306e\u4e2d\u306e\u4e00\u3064\u3067\u30bf\u30b0\u3055\u308c\u305f\u7d50\u679c\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059\uff1a +ReportGenerator.makeBbArtTagTab.taggedRes.msg=\u3053\u306e\u30ec\u30dd\u30fc\u30c8\u306b\u306f\u6b21\u3067\u30bf\u30b0\u3055\u308c\u305f\u7d50\u679c\u3057\u304b\u542b\u307e\u308c\u307e\u305b\u3093\uff1a +ReportGenerator.tagTable.header.resultType=\u7d50\u679c\u30bf\u30a4\u30d7 +ReportGenerator.tagTable.header.tag=\u30bf\u30b0 +ReportGenerator.tagTable.header.comment=\u30b3\u30e1\u30f3\u30c8 +ReportGenerator.tagTable.header.srcFile=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb +ReportGenerator.progress.createdThumb.text=\u30b5\u30e0\u30cd\u30a4\u30eb\u3092\u4f5c\u6210\u4e2d\u2026 +ReportGenerator.thumbnailTable.name=\u30b5\u30e0\u30cd\u30a4\u30eb +ReportGenerator.thumbnailTable.desc=\u30bf\u30b0\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb\u3084\u7d50\u679c\u306b\u95a2\u9023\u3059\u308b\u30a4\u30e1\u30fc\u30b8\u306e\u30b5\u30e0\u30cd\u30a4\u30eb\u304c\u542b\u307e\u308c\u307e\u3059\u3002 +ReportGenerator.writeKwHits.userSrchs=\u30e6\u30fc\u30b6\u691c\u7d22 +ReportGenerator.progress.processingList={0} ({1})\u3092\u51e6\u7406\u4e2d\u2026 ReportGenerator.artTableColHdr.url=URL -ReportGenerator.artTableColHdr.title=\u30BF\u30A4\u30C8\u30EB -ReportGenerator.artTableColHdr.dateCreated=\u4F5C\u6210\u65E5\u4ED8 -ReportGenerator.artTableColHdr.program=\u30D7\u30ED\u30B0\u30E9\u30E0 -ReportGenerator.artTableColHdr.srcFile=\u30BD\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB -ReportGenerator.artTableColHdr.dateTime=\u65E5\u4ED8\uFF0F\u6642\u523B -ReportGenerator.artTableColHdr.name=\u540D\u524D -ReportGenerator.artTableColHdr.value=\u30D0\u30EA\u30E5\u30FC -ReportGenerator.artTableColHdr.dateAccessed=\u30A2\u30AF\u30BB\u30B9\u65E5\u4ED8 -ReportGenerator.artTableColHdr.referrer=\u30EA\u30D5\u30A1\u30E9 -ReportGenerator.artTableColHdr.dest=\u30C7\u30B9\u30C6\u30A3\u30CD\u30FC\u30B7\u30E7\u30F3 -ReportGenerator.artTableColHdr.sourceUrl=\u30BD\u30FC\u30B9URL -ReportGenerator.artTableColHdr.path=\u30D1\u30B9 -ReportGenerator.artTableColHdr.progName=\u30D7\u30ED\u30B0\u30E9\u30E0\u540D -ReportGenerator.artTableColHdr.instDateTime=\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u65E5\u4ED8\uFF0F\u6642\u523B -ReportGenerator.artTableColHdr.preview=\u30D7\u30EC\u30D3\u30E5\u30FC -ReportGenerator.artTableColHdr.file=\u30D5\u30A1\u30A4\u30EB -ReportGenerator.artTableColHdr.size=\u30B5\u30A4\u30BA -ReportGenerator.artTableColHdr.deviceId=\u6A5F\u5668ID -ReportGenerator.artTableColHdr.text=\u30C6\u30AD\u30B9\u30C8 -ReportGenerator.artTableColHdr.domain=\u30C9\u30E1\u30A4\u30F3 -ReportGenerator.artTableColHdr.devManufacturer=\u6A5F\u5668\u30E1\u30FC\u30AB\u30FC -ReportGenerator.artTableColHdr.devModel=\u6A5F\u5668\u30E2\u30C7\u30EB -ReportGenerator.artTableColHdr.personName=\u4EBA\u540D -ReportGenerator.artTableColHdr.phoneNumber=\u96FB\u8A71\u756A\u53F7 -ReportGenerator.artTableColHdr.phoneNumHome=\u96FB\u8A71\u756A\u53F7\uFF08\u81EA\u5B85\uFF09 -ReportGenerator.artTableColHdr.phoneNumOffice=\u96FB\u8A71\u756A\u53F7\uFF08\u4F1A\u793E\uFF09 -ReportGenerator.artTableColHdr.phoneNumMobile=\u96FB\u8A71\u756A\u53F7\uFF08\u643A\u5E2F\uFF09 +ReportGenerator.artTableColHdr.title=\u30bf\u30a4\u30c8\u30eb +ReportGenerator.artTableColHdr.dateCreated=\u4f5c\u6210\u65e5\u4ed8 +ReportGenerator.artTableColHdr.program=\u30d7\u30ed\u30b0\u30e9\u30e0 +ReportGenerator.artTableColHdr.srcFile=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb +ReportGenerator.artTableColHdr.dateTime=\u65e5\u4ed8\uff0f\u6642\u523b +ReportGenerator.artTableColHdr.name=\u540d\u524d +ReportGenerator.artTableColHdr.value=\u30d0\u30ea\u30e5\u30fc +ReportGenerator.artTableColHdr.dateAccessed=\u30a2\u30af\u30bb\u30b9\u65e5\u4ed8 +ReportGenerator.artTableColHdr.referrer=\u30ea\u30d5\u30a1\u30e9 +ReportGenerator.artTableColHdr.dest=\u30c7\u30b9\u30c6\u30a3\u30cd\u30fc\u30b7\u30e7\u30f3 +ReportGenerator.artTableColHdr.sourceUrl=\u30bd\u30fc\u30b9URL +ReportGenerator.artTableColHdr.path=\u30d1\u30b9 +ReportGenerator.artTableColHdr.progName=\u30d7\u30ed\u30b0\u30e9\u30e0\u540d +ReportGenerator.artTableColHdr.instDateTime=\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u65e5\u4ed8\uff0f\u6642\u523b +ReportGenerator.artTableColHdr.preview=\u30d7\u30ec\u30d3\u30e5\u30fc +ReportGenerator.artTableColHdr.file=\u30d5\u30a1\u30a4\u30eb +ReportGenerator.artTableColHdr.size=\u30b5\u30a4\u30ba +ReportGenerator.artTableColHdr.deviceId=\u6a5f\u5668ID +ReportGenerator.artTableColHdr.text=\u30c6\u30ad\u30b9\u30c8 +ReportGenerator.artTableColHdr.domain=\u30c9\u30e1\u30a4\u30f3 +ReportGenerator.artTableColHdr.devManufacturer=\u6a5f\u5668\u30e1\u30fc\u30ab\u30fc +ReportGenerator.artTableColHdr.devModel=\u6a5f\u5668\u30e2\u30c7\u30eb +ReportGenerator.artTableColHdr.personName=\u4eba\u540d +ReportGenerator.artTableColHdr.phoneNumber=\u96fb\u8a71\u756a\u53f7 +ReportGenerator.artTableColHdr.phoneNumHome=\u96fb\u8a71\u756a\u53f7\uff08\u81ea\u5b85\uff09 +ReportGenerator.artTableColHdr.phoneNumOffice=\u96fb\u8a71\u756a\u53f7\uff08\u4f1a\u793e\uff09 +ReportGenerator.artTableColHdr.phoneNumMobile=\u96fb\u8a71\u756a\u53f7\uff08\u643a\u5e2f\uff09 ReportGenerator.artTableColHdr.email=Email -ReportGenerator.artTableColHdr.msgType=\u30E1\u30C3\u30BB\u30FC\u30B8\u30BF\u30A4\u30D7 -ReportGenerator.artTableColHdr.latitude=\u7DEF\u5EA6 -ReportGenerator.artTableColHdr.longitude=\u7D4C\u5EA6 -ReportGenerator.artTableColHdr.dateTaken=\u64AE\u5F71\u65E5\u4ED8 -ReportGenerator.artTableColHdr.subject=\u30B5\u30D6\u30B8\u30A7\u30AF\u30C8 -ReportGenerator.artTableColHdr.calendarEntryType=\u30AB\u30EC\u30F3\u30C0\u30FC\u30A8\u30F3\u30C8\u30EA\u30BF\u30A4\u30D7 -ReportGenerator.artTableColHdr.description=\u8AAC\u660E -ReportGenerator.artTableColHdr.startDateTime=\u958B\u59CB\u65E5\u4ED8\uFF0F\u6642\u523B -ReportGenerator.artTableColHdr.shortCut=\u30B7\u30E7\u30FC\u30C8\u30AB\u30C3\u30C8 -ReportGenerator.artTableColHdr.endDateTime=\u4FEE\u4E86\u65E5\u4ED8\uFF0F\u6642\u523B -ReportGenerator.artTableColHdr.location=\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3 -ReportGenerator.artTableColHdr.deviceName=\u6A5F\u5668\u540D -ReportGenerator.artTableColHdr.deviceAddress=\u6A5F\u5668\u30A2\u30C9\u30EC\u30B9 -ReportGenerator.artTableColHdr.altitude=\u6A19\u9AD8 -ReportGenerator.artTableColHdr.locationAddress=\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\u30A2\u30C9\u30EC\u30B9 -ReportGenerator.artTableColHdr.category=\u30AB\u30C6\u30B4\u30EA\u30FC -ReportGenerator.artTableColHdr.userId=\u30E6\u30FC\u30B6ID -ReportGenerator.artTableColHdr.password=\u30D1\u30B9\u30EF\u30FC\u30C9 -ReportGenerator.artTableColHdr.replytoAddress=\u8FD4\u4FE1\u30A2\u30C9\u30EC\u30B9 -ReportGenerator.artTableColHdr.mailServer=\u30E1\u30FC\u30EB\u30B5\u30FC\u30D0 -ReportGenerator.artTableColHdr.tags=\u30BF\u30B0 -ReportHTML.addThumbRows.dataType.title=\u30BF\u30B0\u4ED8\u3051\u3055\u308C\u305F\u30A4\u30E1\u30FC\u30B8 - {0} -ReportHTML.addThumbRows.dataType.msg=\u30A4\u30E1\u30FC\u30B8\u3092\u542B\u3080\u30BF\u30B0\u4ED8\u3051\u3055\u308C\u305F\u7D50\u679C\u304A\u3088\u3073\u30B3\u30F3\u30C6\u30F3\u30C4\u3002 -ReportHTML.thumbLink.tags=\u30BF\u30B0\uFF1A -ReportHTML.getName.text=\u7D50\u679C - HTML -ReportHTML.getDesc.text=HTML\u5F62\u5F0F\u306E\u7D50\u679C\u304A\u3088\u3073\u30BF\u30B0\u4ED8\u3051\u3055\u308C\u305F\u30A2\u30A4\u30C6\u30E0\u306E\u30EC\u30DD\u30FC\u30C8 -ReportHTML.writeIndex.title=\u30B1\u30FC\u30B9{0}\u306EAutopsy\u30EC\u30DD\u30FC\u30C8 -ReportHTML.writeNav.title=\u30EC\u30DD\u30FC\u30C8\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3 -ReportHTML.writeNav.h1=\u30EC\u30DD\u30FC\u30C8\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3 -ReportHTML.writeNav.summary=\u30B1\u30FC\u30B9\u30B5\u30DE\u30EA\u30FC -ReportHTML.writeSum.title=\u30B1\u30FC\u30B9\u30B5\u30DE\u30EA\u30FC -ReportHTML.writeSum.caseName=\u30B1\u30FC\u30B9\uFF1A -ReportHTML.writeSum.caseNum=\u30B1\u30FC\u30B9\u756A\u53F7\uFF1A -ReportHTML.writeSum.examiner=\u8ABF\u67FB\u62C5\u5F53\u8005\uFF1A -ReportHTML.writeSum.numImages=\u30A4\u30E1\u30FC\u30B8\u6570\uFF1A -ReportHTML.writeSum.path=\u30D1\u30B9\uFF1A -ReportProgressPanel.start.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB -ReportProgressPanel.complete.processLbl.text=\u5B8C\u4E86 -ReportProgressPanel.complete.cancelButton.text=\u5B8C\u4E86 -ReportProgressPanel.cancel.cancelButton.toolTipText=\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F -ReportWizardAction.actionName.text=\u30EC\u30DD\u30FC\u30C8\u3092\u751F\u6210 -ReportWizardAction.reportWiz.title=\u30EC\u30DD\u30FC\u30C8\u3092\u751F\u6210 -ReportWizardAction.toolBarButton.text=\u30EC\u30DD\u30FC\u30C8\u3092\u751F\u6210 -ReportWizardPanel1.nextButton.text=\u6B21 > -ReportWizardPanel2.nextButton.text=\u6B21 > -ReportGenerator.artTableColHdr.direction=\u65B9\u5411 -ReportGenerator.artTableColHdr.fromEmail=\u9001\u4FE1\u5143E\u30E1\u30FC\u30EB -ReportGenerator.artTableColHdr.toEmail=\u9001\u4FE1\u5148E\u30E1\u30FC\u30EB -ReportGenerator.artTableColHdr.fromPhoneNum=\u767A\u4FE1\u8005\u96FB\u8A71\u756A\u53F7 -ReportGenerator.artTableColHdr.toPhoneNum=\u7740\u4FE1\u8005\u96FB\u8A71\u756A\u53F7 -ReportGenerator.artTableColHdr.appName=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u540D -ReportGenerator.artTableColHdr.appPath=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u30D1\u30B9 -ReportHTML.writeIndex.noFrames.msg=\u4F7F\u7528\u3057\u3066\u3044\u308B\u30D6\u30E9\u30A6\u30B6\u306F\u5F0A\u793E\u306E\u30D5\u30EC\u30FC\u30E0\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3068\u306E\u4E92\u63DB\u6027\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -ReportHTML.writeIndex.noFrames.seeNav=\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u30EA\u30F3\u30AF\u306F\u4E0B\u8A18\u306E\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3\u30DA\u30FC\u30B8\u3092\u3054\u89A7\u4E0B\u3055\u3044 -ReportHTML.writeIndex.seeSum=\u307E\u305F\u3001\u30B1\u30FC\u30B9\u30B5\u30DE\u30EA\u30FC\u306F\u4E0B\u8A18\u306E\u30B5\u30DE\u30EA\u30FC\u30DA\u30FC\u30B8\u3092\u3054\u89A7\u4E0B\u3055\u3044\u3002 -ReportHTML.writeSum.warningMsg=\u8B66\u544A\u3001\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B5\u30FC\u30D3\u30B9\u304C\u5B8C\u4E86\u3059\u308B\u524D\u306B\u30EC\u30DD\u30FC\u30C8\u304C\u5B9F\u884C\u3055\u308C\u307E\u3057\u305F\uFF01 -ReportHTML.writeSum.noExaminer=\u8ABF\u67FB\u62C5\u5F53\u8005\u7121\u3057 -ReportHTML.writeSum.imageInfoHeading=

\u30A4\u30E1\u30FC\u30B8\u60C5\u5831\uFF1A

-ReportHTML.writeSum.timezone=\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3\uFF1A -ReportProgressPanel.progress.queuing=\u30AD\u30E5\u30FC\u30A4\u30F3\u30B0\u2026 -ReportProgressPanel.initPathLabel.noFile=\u30EC\u30DD\u30FC\u30C8\u30D5\u30A1\u30A4\u30EB\u7121\u3057 -ReportProgressPanel.start.progress.text=\u30EC\u30DD\u30FC\u30C8\u958B\u59CB\u4E2D\u2026 -ReportProgressPanel.cancel.procLbl.text=\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F -ReportVisualPanel1.getName.text=\u30EC\u30DD\u30FC\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u9078\u629E\u304A\u3088\u3073\u8A2D\u5B9A -ReportVisualPanel2.getName.text=\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u30EC\u30DD\u30FC\u30C8\u3092\u8A2D\u5B9A -ReportWizardFileOptionsPanel.finishButton.text=\u7D42\u4E86 -ReportWizardFileOptionsVisualPanel.getName.text=\u30D5\u30A1\u30A4\u30EB\u30EC\u30DD\u30FC\u30C8\u3092\u8A2D\u5B9A -ReportWizardPanel1.finishButton.text=\u7D42\u4E86 -ReportWizardPanel2.finishButton.text=\u7D42\u4E86 -ReportHTML.writeSum.reportGenOn.text={0}\u306BHTML\u30EC\u30DD\u30FC\u30C8\u306F\u751F\u6210\u3055\u308C\u307E\u3057\u305F -ReportHTML.writeSum.noCaseNum=\u30B1\u30FC\u30B9\u756A\u53F7\u304C\u3042\u308A\u307E\u305B\u3093 -ReportGenerator.errors.reportErrorTitle=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -ReportGenerator.errors.reportErrorText=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\uFF1A -ReportKML.getDesc.text=\u95A2\u9023\u30D5\u30A1\u30A4\u30EB\u306E\u5EA7\u6A19\u3092\u542B\u3080KML\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u306E\u30EC\u30DD\u30FC\u30C8\u3002\u3053\u306E\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u306FGoogle Earth\u30D3\u30E5\u30FC\u306B\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002 +ReportGenerator.artTableColHdr.msgType=\u30e1\u30c3\u30bb\u30fc\u30b8\u30bf\u30a4\u30d7 +ReportGenerator.artTableColHdr.latitude=\u7def\u5ea6 +ReportGenerator.artTableColHdr.longitude=\u7d4c\u5ea6 +ReportGenerator.artTableColHdr.dateTaken=\u64ae\u5f71\u65e5\u4ed8 +ReportGenerator.artTableColHdr.subject=\u30b5\u30d6\u30b8\u30a7\u30af\u30c8 +ReportGenerator.artTableColHdr.calendarEntryType=\u30ab\u30ec\u30f3\u30c0\u30fc\u30a8\u30f3\u30c8\u30ea\u30bf\u30a4\u30d7 +ReportGenerator.artTableColHdr.description=\u8aac\u660e +ReportGenerator.artTableColHdr.startDateTime=\u958b\u59cb\u65e5\u4ed8\uff0f\u6642\u523b +ReportGenerator.artTableColHdr.shortCut=\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8 +ReportGenerator.artTableColHdr.endDateTime=\u4fee\u4e86\u65e5\u4ed8\uff0f\u6642\u523b +ReportGenerator.artTableColHdr.location=\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3 +ReportGenerator.artTableColHdr.deviceName=\u6a5f\u5668\u540d +ReportGenerator.artTableColHdr.deviceAddress=\u6a5f\u5668\u30a2\u30c9\u30ec\u30b9 +ReportGenerator.artTableColHdr.altitude=\u6a19\u9ad8 +ReportGenerator.artTableColHdr.locationAddress=\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30c9\u30ec\u30b9 +ReportGenerator.artTableColHdr.category=\u30ab\u30c6\u30b4\u30ea\u30fc +ReportGenerator.artTableColHdr.userId=\u30e6\u30fc\u30b6ID +ReportGenerator.artTableColHdr.password=\u30d1\u30b9\u30ef\u30fc\u30c9 +ReportGenerator.artTableColHdr.replytoAddress=\u8fd4\u4fe1\u30a2\u30c9\u30ec\u30b9 +ReportGenerator.artTableColHdr.mailServer=\u30e1\u30fc\u30eb\u30b5\u30fc\u30d0 +ReportGenerator.artTableColHdr.tags=\u30bf\u30b0 +ReportHTML.addThumbRows.dataType.title=\u30bf\u30b0\u4ed8\u3051\u3055\u308c\u305f\u30a4\u30e1\u30fc\u30b8 - {0} +ReportHTML.addThumbRows.dataType.msg=\u30a4\u30e1\u30fc\u30b8\u3092\u542b\u3080\u30bf\u30b0\u4ed8\u3051\u3055\u308c\u305f\u7d50\u679c\u304a\u3088\u3073\u30b3\u30f3\u30c6\u30f3\u30c4\u3002 +ReportHTML.thumbLink.tags=\u30bf\u30b0\uff1a +ReportHTML.getName.text=\u7d50\u679c - HTML +ReportHTML.getDesc.text=HTML\u5f62\u5f0f\u306e\u7d50\u679c\u304a\u3088\u3073\u30bf\u30b0\u4ed8\u3051\u3055\u308c\u305f\u30a2\u30a4\u30c6\u30e0\u306e\u30ec\u30dd\u30fc\u30c8 +ReportHTML.writeIndex.title=\u30b1\u30fc\u30b9{0}\u306eAutopsy\u30ec\u30dd\u30fc\u30c8 +ReportHTML.writeNav.title=\u30ec\u30dd\u30fc\u30c8\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3 +ReportHTML.writeNav.h1=\u30ec\u30dd\u30fc\u30c8\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3 +ReportHTML.writeNav.summary=\u30b1\u30fc\u30b9\u30b5\u30de\u30ea\u30fc +ReportHTML.writeSum.title=\u30b1\u30fc\u30b9\u30b5\u30de\u30ea\u30fc +ReportHTML.writeSum.caseName=\u30b1\u30fc\u30b9\uff1a +ReportHTML.writeSum.caseNum=\u30b1\u30fc\u30b9\u756a\u53f7\uff1a +ReportHTML.writeSum.examiner=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a +ReportHTML.writeSum.numImages=\u30a4\u30e1\u30fc\u30b8\u6570\uff1a +ReportHTML.writeSum.path=\u30d1\u30b9\uff1a +ReportProgressPanel.start.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +ReportProgressPanel.complete.processLbl.text=\u5b8c\u4e86 +ReportProgressPanel.complete.cancelButton.text=\u5b8c\u4e86 +ReportProgressPanel.cancel.cancelButton.toolTipText=\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f +ReportWizardAction.actionName.text=\u30ec\u30dd\u30fc\u30c8\u3092\u751f\u6210 +ReportWizardAction.reportWiz.title=\u30ec\u30dd\u30fc\u30c8\u3092\u751f\u6210 +ReportWizardAction.toolBarButton.text=\u30ec\u30dd\u30fc\u30c8\u3092\u751f\u6210 +ReportWizardPanel1.nextButton.text=\u6b21 > +ReportWizardPanel2.nextButton.text=\u6b21 > +ReportGenerator.artTableColHdr.direction=\u65b9\u5411 +ReportGenerator.artTableColHdr.fromEmail=\u9001\u4fe1\u5143E\u30e1\u30fc\u30eb +ReportGenerator.artTableColHdr.toEmail=\u9001\u4fe1\u5148E\u30e1\u30fc\u30eb +ReportGenerator.artTableColHdr.fromPhoneNum=\u767a\u4fe1\u8005\u96fb\u8a71\u756a\u53f7 +ReportGenerator.artTableColHdr.toPhoneNum=\u7740\u4fe1\u8005\u96fb\u8a71\u756a\u53f7 +ReportGenerator.artTableColHdr.appName=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u540d +ReportGenerator.artTableColHdr.appPath=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d1\u30b9 +ReportHTML.writeIndex.noFrames.msg=\u4f7f\u7528\u3057\u3066\u3044\u308b\u30d6\u30e9\u30a6\u30b6\u306f\u5f0a\u793e\u306e\u30d5\u30ec\u30fc\u30e0\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3068\u306e\u4e92\u63db\u6027\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +ReportHTML.writeIndex.noFrames.seeNav=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30ea\u30f3\u30af\u306f\u4e0b\u8a18\u306e\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3\u30da\u30fc\u30b8\u3092\u3054\u89a7\u4e0b\u3055\u3044 +ReportHTML.writeIndex.seeSum=\u307e\u305f\u3001\u30b1\u30fc\u30b9\u30b5\u30de\u30ea\u30fc\u306f\u4e0b\u8a18\u306e\u30b5\u30de\u30ea\u30fc\u30da\u30fc\u30b8\u3092\u3054\u89a7\u4e0b\u3055\u3044\u3002 +ReportHTML.writeSum.warningMsg=\u8b66\u544a\u3001\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b5\u30fc\u30d3\u30b9\u304c\u5b8c\u4e86\u3059\u308b\u524d\u306b\u30ec\u30dd\u30fc\u30c8\u304c\u5b9f\u884c\u3055\u308c\u307e\u3057\u305f\uff01 +ReportHTML.writeSum.noExaminer=\u8abf\u67fb\u62c5\u5f53\u8005\u7121\u3057 +ReportHTML.writeSum.imageInfoHeading=

\u30a4\u30e1\u30fc\u30b8\u60c5\u5831\uff1a

+ReportHTML.writeSum.timezone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\uff1a +ReportProgressPanel.progress.queuing=\u30ad\u30e5\u30fc\u30a4\u30f3\u30b0\u2026 +ReportProgressPanel.initPathLabel.noFile=\u30ec\u30dd\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u7121\u3057 +ReportProgressPanel.start.progress.text=\u30ec\u30dd\u30fc\u30c8\u958b\u59cb\u4e2d\u2026 +ReportProgressPanel.cancel.procLbl.text=\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f +ReportVisualPanel1.getName.text=\u30ec\u30dd\u30fc\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u9078\u629e\u304a\u3088\u3073\u8a2d\u5b9a +ReportVisualPanel2.getName.text=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30ec\u30dd\u30fc\u30c8\u3092\u8a2d\u5b9a +ReportWizardFileOptionsPanel.finishButton.text=\u7d42\u4e86 +ReportWizardFileOptionsVisualPanel.getName.text=\u30d5\u30a1\u30a4\u30eb\u30ec\u30dd\u30fc\u30c8\u3092\u8a2d\u5b9a +ReportWizardPanel1.finishButton.text=\u7d42\u4e86 +ReportWizardPanel2.finishButton.text=\u7d42\u4e86 +ReportHTML.writeSum.reportGenOn.text={0}\u306bHTML\u30ec\u30dd\u30fc\u30c8\u306f\u751f\u6210\u3055\u308c\u307e\u3057\u305f +ReportHTML.writeSum.noCaseNum=\u30b1\u30fc\u30b9\u756a\u53f7\u304c\u3042\u308a\u307e\u305b\u3093 +ReportGenerator.errors.reportErrorTitle=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +ReportGenerator.errors.reportErrorText=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a +ReportKML.getDesc.text=\u95a2\u9023\u30d5\u30a1\u30a4\u30eb\u306e\u5ea7\u6a19\u3092\u542b\u3080KML\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u306e\u30ec\u30dd\u30fc\u30c8\u3002\u3053\u306e\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u306fGoogle Earth\u30d3\u30e5\u30fc\u306b\u4f7f\u7528\u3067\u304d\u307e\u3059\u3002 ReportKML.getName.text=Google Earth/KML -ReportKML.progress.loading=\u30D5\u30A1\u30A4\u30EB\u306E\u8AAD\u307F\u8FBC\u307F\u4E2D\u2026 -ReportKML.progress.querying=\u30D5\u30A1\u30A4\u30EB\u306E\u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u4E2D\u2026 -ReportBodyFile.generateReport.srcModuleName.text=TSK\u30DC\u30C7\u30A3\u30D5\u30A1\u30A4\u30EB -ReportExcel.endReport.srcModuleName.text=Excel\u30EC\u30DD\u30FC\u30C8 -ReportGenerator.artTableColHdr.extension.text=\u62E1\u5F35\u5B50 -ReportGenerator.artTableColHdr.mimeType.text=MIME\u30BF\u30A4\u30D7 -ReportHTML.writeIndex.srcModuleName.text=HTML\u30EC\u30DD\u30FC\u30C8 -ReportKML.genReport.srcModuleName.text=KML\u30EC\u30DD\u30FC\u30C8 -ReportGenerator.artTableColHdr.associatedArtifact=\u95A2\u4FC2\u3059\u308B\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8 -ReportGenerator.artTableColHdr.count=\u30AB\u30A6\u30F3\u30C8 -ReportGenerator.artTableColHdr.devMake=\u6A5F\u5668\u578B\u540D -ReportGenerator.artTableColHdr.latitudeEnd=\u5230\u7740\u7DEF\u5EA6 -ReportGenerator.artTableColHdr.latitudeStart=\u51FA\u767A\u7DEF\u5EA6 -ReportGenerator.artTableColHdr.localPath=\u30ED\u30FC\u30AB\u30EB\u30D1\u30B9 -ReportGenerator.artTableColHdr.longitudeEnd=\u5230\u7740\u7D4C\u5EA6 -ReportGenerator.artTableColHdr.longitudeStart=\u51FA\u767A\u7D4C\u5EA6 -ReportGenerator.artTableColHdr.osInstallDate.text=\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u65E5\u4ED8 -ReportGenerator.artTableColHdr.osName.text=\u30AA\u30DA\u30EC\u30FC\u30C6\u30A3\u30F3\u30B0\u30B7\u30B9\u30C6\u30E0\u540D -ReportGenerator.artTableColHdr.processorArchitecture.text=\u30D7\u30ED\u30BB\u30C3\u30B5\u30A2\u30FC\u30AD\u30C6\u30AF\u30C1\u30E3 -ReportGenerator.artTableColHdr.readStatus=\u8AAD\u307F\u53D6\u308A\u4E2D\u30B9\u30C6\u30FC\u30BF\u30B9 -ReportGenerator.artTableColHdr.remotePath=\u30EA\u30E2\u30FC\u30C8\u30D1\u30B9 -ReportGenerator.artTableColHdr.tskDateTimeRcvd=\u53D7\u4FE1\u65E5 -ReportGenerator.artTableColHdr.tskDateTimeSent=\u9001\u4FE1\u65E5 +ReportKML.progress.loading=\u30d5\u30a1\u30a4\u30eb\u306e\u8aad\u307f\u8fbc\u307f\u4e2d\u2026 +ReportKML.progress.querying=\u30d5\u30a1\u30a4\u30eb\u306e\u30af\u30a8\u30ea\u3092\u5b9f\u884c\u4e2d\u2026 +ReportBodyFile.generateReport.srcModuleName.text=TSK\u30dc\u30c7\u30a3\u30d5\u30a1\u30a4\u30eb +ReportExcel.endReport.srcModuleName.text=Excel\u30ec\u30dd\u30fc\u30c8 +ReportGenerator.artTableColHdr.extension.text=\u62e1\u5f35\u5b50 +ReportGenerator.artTableColHdr.mimeType.text=MIME\u30bf\u30a4\u30d7 +ReportHTML.writeIndex.srcModuleName.text=HTML\u30ec\u30dd\u30fc\u30c8 +ReportKML.genReport.srcModuleName.text=KML\u30ec\u30dd\u30fc\u30c8 +ReportGenerator.artTableColHdr.associatedArtifact=\u95a2\u4fc2\u3059\u308b\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8 +ReportGenerator.artTableColHdr.count=\u30ab\u30a6\u30f3\u30c8 +ReportGenerator.artTableColHdr.devMake=\u6a5f\u5668\u578b\u540d +ReportGenerator.artTableColHdr.latitudeEnd=\u5230\u7740\u7def\u5ea6 +ReportGenerator.artTableColHdr.latitudeStart=\u51fa\u767a\u7def\u5ea6 +ReportGenerator.artTableColHdr.localPath=\u30ed\u30fc\u30ab\u30eb\u30d1\u30b9 +ReportGenerator.artTableColHdr.longitudeEnd=\u5230\u7740\u7d4c\u5ea6 +ReportGenerator.artTableColHdr.longitudeStart=\u51fa\u767a\u7d4c\u5ea6 +ReportGenerator.artTableColHdr.osInstallDate.text=\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u65e5\u4ed8 +ReportGenerator.artTableColHdr.osName.text=\u30aa\u30da\u30ec\u30fc\u30c6\u30a3\u30f3\u30b0\u30b7\u30b9\u30c6\u30e0\u540d +ReportGenerator.artTableColHdr.processorArchitecture.text=\u30d7\u30ed\u30bb\u30c3\u30b5\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3 +ReportGenerator.artTableColHdr.readStatus=\u8aad\u307f\u53d6\u308a\u4e2d\u30b9\u30c6\u30fc\u30bf\u30b9 +ReportGenerator.artTableColHdr.remotePath=\u30ea\u30e2\u30fc\u30c8\u30d1\u30b9 +ReportGenerator.artTableColHdr.tskDateTimeRcvd=\u53d7\u4fe1\u65e5 +ReportGenerator.artTableColHdr.tskDateTimeSent=\u9001\u4fe1\u65e5 ReportGenerator.artTableColHdr.tskEmailBcc=E-Mail BCC ReportGenerator.artTableColHdr.tskEmailCc=E-Mail CC -ReportGenerator.artTableColHdr.tskEmailFrom=E-Mail\u9001\u4FE1\u5143 -ReportGenerator.artTableColHdr.tskEmailTo=E-Mail\u9001\u4FE1\u5148 -ReportGenerator.artTableColHdr.tskGpsRouteCategory=\u30AB\u30C6\u30B4\u30EA -ReportGenerator.artTableColHdr.tskInterestingFilesCategory=\u30EB\u30FC\u30EB -ReportGenerator.artTableColHdr.tskMsgId=\u30E1\u30C3\u30BB\u30FC\u30B8ID -ReportGenerator.artTableColHdr.tskPath=\u30D1\u30B9 -ReportGenerator.artTableColHdr.tskSetName=\u30BB\u30C3\u30C8\u540D -ReportGenerator.artTableColHdr.tskSubject=\u30B5\u30D6\u30B8\u30A7\u30AF\u30C8 -ReportGenerator.artTableColHdr.urlDomainDecoded=URL\u30C9\u30E1\u30A4\u30F3 -ReportGenerator.artTableColHdr.userName=\u30E6\u30FC\u30B6\u540D -ReportGenerator.errList.coreExceptionWhileGenRptRow=\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u30EC\u30DD\u30FC\u30C8\u7528\u30ED\u30FC\u30C7\u30FC\u30BF\u306E\u751F\u6210\u4E2D\u306B\u30B3\u30A2\u30A8\u30AF\u30BB\u30D7\u30B7\u30E7\u30F3\uFF08\u4F8B\u5916\uFF09\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F -ReportGenerator.errList.errGetContentFromBBArtifact=Blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u304B\u3089\u30EC\u30DD\u30FC\u30C8\u7528\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u53D6\u5F97\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.errList.failedGetAbstractFileByID=ID\u306B\u57FA\u3065\u304D\u30A2\u30D6\u30B9\u30C8\u30E9\u30AF\u30C8\u30D5\u30A1\u30A4\u30EB\u3092\u53D6\u5F97\u3059\u308B\u306E\u3092\u5931\u6557\u3057\u307E\u3057\u305F -ReportGenerator.errList.failedGetBBArtifacts=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u4E2D\u306BBlackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.errList.failedGetBBArtifactTags=Blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u30BF\u30B0\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.errList.failedGetBBAttribs=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u4E2D\u306BBlackboard\u5C5E\u6027\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.errList.failedGetContentTags=\u30B3\u30F3\u30C6\u30F3\u30C4\u30BF\u30B0\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.errList.failedMakeRptFolder=\u30EC\u30DD\u30FC\u30C8\u30D5\u30A9\u30EB\u30C0\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u304C\u3067\u304D\u306A\u3044\u304B\u3082\u3057\u308C\u307E\u305B\u3093\u3002 -ReportGenerator.errList.failedQueryHashsetHits=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u30D2\u30C3\u30C8\u3092\u30AF\u30A8\u30EA\u3059\u308B\u306E\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.errList.failedQueryHashsetLists=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u30EA\u30B9\u30C8\u3092\u30AF\u30A8\u30EA\u3059\u308B\u306E\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.errList.failedQueryKWLists=\u30AD\u30FC\u30EF\u30FC\u30C9\u30EA\u30B9\u30C8\u3092\u30AF\u30A8\u30EA\u3059\u308B\u306E\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.errList.failedQueryKWs=\u30AD\u30FC\u30EF\u30FC\u30C9\u3092\u30AF\u30A8\u30EA\u3059\u308B\u306E\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -ReportGenerator.htmlOutput.header.comment=\u30B3\u30E1\u30F3\u30C8 -ReportGenerator.htmlOutput.header.file=\u30D5\u30A1\u30A4\u30EB -ReportGenerator.htmlOutput.header.hash=\u30CF\u30C3\u30B7\u30E5 -ReportGenerator.htmlOutput.header.size=\u30B5\u30A4\u30BA\uFF08\u30D0\u30A4\u30C8\uFF09 -ReportGenerator.htmlOutput.header.tag=\u30BF\u30B0 -ReportGenerator.htmlOutput.header.timeAccessed=\u30A2\u30AF\u30BB\u30B9\u65E5\u6642 -ReportGenerator.htmlOutput.header.timeChanged=\u5909\u66F4\u65E5\u6642 -ReportGenerator.htmlOutput.header.timeCreated=\u4F5C\u6210\u65E5\u6642 -ReportGenerator.htmlOutput.header.timeModified=\u4FEE\u6B63\u65E5\u6642 -ReportGenerator.notifyErr.errsDuringRptGen=\u30EC\u30DD\u30FC\u30C8\u751F\u6210\u4E2D\u306E\u30A8\u30E9\u30FC\uFF1A -ReportGenerator.errList.failedGetAbstractFileFromID=ID\u306B\u57FA\u3065\u304D\u30A2\u30D6\u30B9\u30C8\u30E9\u30AF\u30C8\u30D5\u30A1\u30A4\u30EB\u3092\u53D6\u5F97\u3059\u308B\u306E\u3092\u5931\u6557\u3057\u307E\u3057\u305F -ReportKML.getFilePath.text=\u30EC\u30DD\u30FC\u30C8KML.kml -ReportVisualPanel1.invalidModuleWarning=\u7121\u52B9\u306A\u30EC\u30DD\u30FC\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB({0})\u306B\u906D\u9047\u3057\u307E\u3057\u305F -ReportGenerationPanel.confDlg.cancelReport.msg=\u672C\u5F53\u306B\u30EC\u30DD\u30FC\u30C8\u3092\u30AD\u30E3\u30F3\u30BB\u30EB\u3057\u307E\u3059\u304B\uFF1F -ReportProgressPanel.complete.processLb2.text=\u5B8C\u4E86\u3057\u307E\u3057\u305F\u304C\u3001\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -ReportGenerationPanel.cancelButton.actionCommand=\u30AD\u30E3\u30F3\u30BB\u30EB -ReportGenerationPanel.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB \ No newline at end of file +ReportGenerator.artTableColHdr.tskEmailFrom=E-Mail\u9001\u4fe1\u5143 +ReportGenerator.artTableColHdr.tskEmailTo=E-Mail\u9001\u4fe1\u5148 +ReportGenerator.artTableColHdr.tskGpsRouteCategory=\u30ab\u30c6\u30b4\u30ea +ReportGenerator.artTableColHdr.tskInterestingFilesCategory=\u30eb\u30fc\u30eb +ReportGenerator.artTableColHdr.tskMsgId=\u30e1\u30c3\u30bb\u30fc\u30b8ID +ReportGenerator.artTableColHdr.tskPath=\u30d1\u30b9 +ReportGenerator.artTableColHdr.tskSetName=\u30bb\u30c3\u30c8\u540d +ReportGenerator.artTableColHdr.tskSubject=\u30b5\u30d6\u30b8\u30a7\u30af\u30c8 +ReportGenerator.artTableColHdr.urlDomainDecoded=URL\u30c9\u30e1\u30a4\u30f3 +ReportGenerator.artTableColHdr.userName=\u30e6\u30fc\u30b6\u540d +ReportGenerator.errList.coreExceptionWhileGenRptRow=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30ec\u30dd\u30fc\u30c8\u7528\u30ed\u30fc\u30c7\u30fc\u30bf\u306e\u751f\u6210\u4e2d\u306b\u30b3\u30a2\u30a8\u30af\u30bb\u30d7\u30b7\u30e7\u30f3\uff08\u4f8b\u5916\uff09\u304c\u691c\u51fa\u3055\u308c\u307e\u3057\u305f +ReportGenerator.errList.errGetContentFromBBArtifact=Blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u304b\u3089\u30ec\u30dd\u30fc\u30c8\u7528\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.errList.failedGetAbstractFileByID=ID\u306b\u57fa\u3065\u304d\u30a2\u30d6\u30b9\u30c8\u30e9\u30af\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u53d6\u5f97\u3059\u308b\u306e\u3092\u5931\u6557\u3057\u307e\u3057\u305f +ReportGenerator.errList.failedGetBBArtifacts=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306bBlackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.errList.failedGetBBArtifactTags=Blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30bf\u30b0\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.errList.failedGetBBAttribs=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306bBlackboard\u5c5e\u6027\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.errList.failedGetContentTags=\u30b3\u30f3\u30c6\u30f3\u30c4\u30bf\u30b0\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.errList.failedMakeRptFolder=\u30ec\u30dd\u30fc\u30c8\u30d5\u30a9\u30eb\u30c0\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u304c\u3067\u304d\u306a\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 +ReportGenerator.errList.failedQueryHashsetHits=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u30d2\u30c3\u30c8\u3092\u30af\u30a8\u30ea\u3059\u308b\u306e\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.errList.failedQueryHashsetLists=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u30ea\u30b9\u30c8\u3092\u30af\u30a8\u30ea\u3059\u308b\u306e\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.errList.failedQueryKWLists=\u30ad\u30fc\u30ef\u30fc\u30c9\u30ea\u30b9\u30c8\u3092\u30af\u30a8\u30ea\u3059\u308b\u306e\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.errList.failedQueryKWs=\u30ad\u30fc\u30ef\u30fc\u30c9\u3092\u30af\u30a8\u30ea\u3059\u308b\u306e\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +ReportGenerator.htmlOutput.header.comment=\u30b3\u30e1\u30f3\u30c8 +ReportGenerator.htmlOutput.header.file=\u30d5\u30a1\u30a4\u30eb +ReportGenerator.htmlOutput.header.hash=\u30cf\u30c3\u30b7\u30e5 +ReportGenerator.htmlOutput.header.size=\u30b5\u30a4\u30ba\uff08\u30d0\u30a4\u30c8\uff09 +ReportGenerator.htmlOutput.header.tag=\u30bf\u30b0 +ReportGenerator.htmlOutput.header.timeAccessed=\u30a2\u30af\u30bb\u30b9\u65e5\u6642 +ReportGenerator.htmlOutput.header.timeCreated=\u4f5c\u6210\u65e5\u6642 +ReportGenerator.htmlOutput.header.timeModified=\u4fee\u6b63\u65e5\u6642 +ReportGenerator.notifyErr.errsDuringRptGen=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306e\u30a8\u30e9\u30fc\uff1a +ReportGenerator.errList.failedGetAbstractFileFromID=ID\u306b\u57fa\u3065\u304d\u30a2\u30d6\u30b9\u30c8\u30e9\u30af\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u53d6\u5f97\u3059\u308b\u306e\u3092\u5931\u6557\u3057\u307e\u3057\u305f +ReportKML.getFilePath.text=\u30ec\u30dd\u30fc\u30c8KML.kml +ReportVisualPanel1.invalidModuleWarning=\u7121\u52b9\u306a\u30ec\u30dd\u30fc\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb({0})\u306b\u906d\u9047\u3057\u307e\u3057\u305f +ReportGenerationPanel.confDlg.cancelReport.msg=\u672c\u5f53\u306b\u30ec\u30dd\u30fc\u30c8\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3059\u304b\uff1f +ReportProgressPanel.complete.processLb2.text=\u5b8c\u4e86\u3057\u307e\u3057\u305f\u304c\u3001\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +ReportGenerationPanel.cancelButton.actionCommand=\u30ad\u30e3\u30f3\u30bb\u30eb +ReportGenerationPanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerationPanel.form b/Core/src/org/sleuthkit/autopsy/report/ReportGenerationPanel.form index f7da786aa4..86a4cbe37d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerationPanel.form +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerationPanel.form @@ -26,22 +26,16 @@ - - - - - - - - - - + + + + @@ -51,19 +45,13 @@ - - - - - - - + - + @@ -102,77 +90,30 @@
- + - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerationPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerationPanel.java index debc77e343..0064b14f69 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerationPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,69 +20,89 @@ package org.sleuthkit.autopsy.report; import java.awt.*; import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; import javax.swing.Box; import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; +/** + * A panel that displays a panel used by a report generation module to show + * progress. It provides OK and Cancel buttons. + */ class ReportGenerationPanel extends javax.swing.JPanel { - private GridBagConstraints c; - ReportProgressPanel progressPanel; - private Component glue; + private static final long serialVersionUID = 1L; + private final GridBagConstraints constraints; + private final Component glue; private ActionListener actionListener; + ReportProgressPanel progressPanel; /** - * Creates new form ReportGenerationPanel + * Constructs a panel that displays a panel used by a report generation + * module to show progress. It provides OK and Cancel buttons. */ - public ReportGenerationPanel() { + ReportGenerationPanel() { initComponents(); - customInit(); - } - - private void customInit() { reportPanel.setLayout(new GridBagLayout()); - c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - c.gridx = 0; - c.gridy = 0; - c.weightx = 1.0; + constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.BOTH; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; glue = Box.createVerticalGlue(); } /** - * Add a ReportProgressPanel to this panel with the given report name and - * path. + * Adds a panel used by a report generation module to show progress to this + * panel. * - * @param reportName report name - * @param reportPath report path + * @param reportName The report name. + * @param reportPath The report file path * - * @return ReportProgressPanel progress panel to update + * @return The report generation progress panel. */ - public ReportProgressPanel addReport(String reportName, String reportPath) { - // Remove the glue + ReportProgressPanel addReport(String reportName, String reportPath) { + /* + * Remove the "glue." + */ reportPanel.remove(glue); progressPanel = new ReportProgressPanel(reportName, reportPath); - c.weighty = 0.0; - c.anchor = GridBagConstraints.NORTH; - reportPanel.add(progressPanel, c); - c.gridy++; + constraints.weighty = 0.0; + constraints.anchor = GridBagConstraints.NORTH; + reportPanel.add(progressPanel, constraints); + constraints.gridy++; - // Add the glue back to the bottom - c.weighty = 1.0; - c.anchor = GridBagConstraints.PAGE_END; - reportPanel.add(glue, c); + /* + * Add the "glue" back to the bottom of the panel. + */ + constraints.weighty = 1.0; + constraints.anchor = GridBagConstraints.PAGE_END; + reportPanel.add(glue, constraints); - // 80 px per progressPanel. + /* + * Use 80 pixels per progress panel. This is a leftover from when this + * panel used to show multiple report progress panels. + */ reportPanel.setPreferredSize(new Dimension(600, 1 * 80)); reportPanel.repaint(); + progressPanel.addPropertyChangeListener((PropertyChangeEvent evt) -> { + String propName = evt.getPropertyName(); + if (propName.equals(ReportProgressPanel.ReportStatus.COMPLETE.toString()) + || propName.equals(ReportProgressPanel.ReportStatus.CANCELED.toString())) { + SwingUtilities.invokeLater(() -> { + cancelButton.setEnabled(false); + }); + } + }); return progressPanel; } /** - * Close this panel and it's dialog if all reports are done. + * Closes this panel and its dialog if all reports are done. */ void close() { boolean closeable = true; @@ -105,6 +125,15 @@ class ReportGenerationPanel extends javax.swing.JPanel { } } + /** + * Adds a close action listener to this panel. + * + * @param listener The listener to add. + */ + void addCloseAction(ActionListener listener) { + this.actionListener = listener; + } + /** * 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 @@ -116,11 +145,7 @@ class ReportGenerationPanel extends javax.swing.JPanel { closeButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); - reportScrollPane = new javax.swing.JScrollPane(); reportPanel = new javax.swing.JPanel(); - titleLabel = new javax.swing.JLabel(); - titleSeparator = new javax.swing.JSeparator(); - optionSeparator = new javax.swing.JSeparator(); setFont(getFont().deriveFont(getFont().getStyle() & ~java.awt.Font.BOLD, 11)); setPreferredSize(new java.awt.Dimension(700, 400)); @@ -142,10 +167,6 @@ class ReportGenerationPanel extends javax.swing.JPanel { } }); - reportScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(java.awt.SystemColor.activeCaptionBorder)); - reportScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); - reportScrollPane.setFont(reportScrollPane.getFont().deriveFont(reportScrollPane.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - reportPanel.setFont(reportPanel.getFont().deriveFont(reportPanel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); reportPanel.setPreferredSize(new java.awt.Dimension(600, 400)); @@ -153,53 +174,33 @@ class ReportGenerationPanel extends javax.swing.JPanel { reportPanel.setLayout(reportPanelLayout); reportPanelLayout.setHorizontalGroup( reportPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 661, Short.MAX_VALUE) + .addGap(0, 0, Short.MAX_VALUE) ); reportPanelLayout.setVerticalGroup( reportPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 400, Short.MAX_VALUE) + .addGap(0, 344, Short.MAX_VALUE) ); - reportScrollPane.setViewportView(reportPanel); - - titleLabel.setFont(titleLabel.getFont().deriveFont(titleLabel.getFont().getStyle() | java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(titleLabel, org.openide.util.NbBundle.getMessage(ReportGenerationPanel.class, "ReportGenerationPanel.titleLabel.text")); // NOI18N - - titleSeparator.setForeground(new java.awt.Color(0, 0, 0)); - - optionSeparator.setForeground(new java.awt.Color(0, 0, 0)); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(optionSeparator) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(reportScrollPane) - .addComponent(titleSeparator, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(titleLabel) - .addGap(0, 522, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 546, Short.MAX_VALUE) .addComponent(cancelButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(closeButton))) + .addComponent(closeButton)) + .addComponent(reportPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 680, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(titleLabel) - .addGap(0, 0, 0) - .addComponent(titleSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(reportScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 290, Short.MAX_VALUE) - .addGap(18, 18, 18) - .addComponent(optionSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(reportPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 344, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(closeButton) @@ -225,17 +226,10 @@ class ReportGenerationPanel extends javax.swing.JPanel { } }//GEN-LAST:event_cancelButtonActionPerformed - void addCloseAction(ActionListener l) { - this.actionListener = l; - } - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton cancelButton; private javax.swing.JButton closeButton; - private javax.swing.JSeparator optionSeparator; private javax.swing.JPanel reportPanel; - private javax.swing.JScrollPane reportScrollPane; - private javax.swing.JLabel titleLabel; - private javax.swing.JSeparator titleSeparator; // End of variables declaration//GEN-END:variables + } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index e0d201f4af..1f49588837 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -53,10 +53,12 @@ import javax.swing.SwingWorker; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -653,6 +655,18 @@ class ReportGenerator { } ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment())); + Content content = tag.getContent(); + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + + // Add metadata about the file to HTML output + rowData.add(file.getMtimeAsDate()); + rowData.add(file.getCtimeAsDate()); + rowData.add(file.getAtimeAsDate()); + rowData.add(file.getCrtimeAsDate()); + rowData.add(Long.toString(file.getSize())); + rowData.add(file.getMd5Hash()); + } for (TableReportModule module : tableModules) { // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. if (module instanceof ReportHTML) { @@ -684,6 +698,7 @@ class ReportGenerator { NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports", ex.getCause()); //NON-NLS logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS } // catch and ignore if we were cancelled catch (java.util.concurrent.CancellationException ex) { @@ -1759,11 +1774,10 @@ class ReportGenerator { * * @return String unique path */ - private String getFileUniquePath(long objId) { + private String getFileUniquePath(Content content) { try { - AbstractFile af = skCase.getAbstractFileById(objId); - if (af != null) { - return af.getUniquePath(); + if (content != null) { + return content.getUniquePath(); } else { return ""; } @@ -1785,11 +1799,17 @@ class ReportGenerator { private List attributes; private HashSet tags; private List rowData = null; + private Content content; ArtifactData(BlackboardArtifact artifact, List attrs, HashSet tags) { this.artifact = artifact; this.attributes = attrs; this.tags = tags; + try { + this.content = Case.getCurrentCase().getSleuthkitCase().getContentById(artifact.getObjectID()); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Could not get content from database"); + } } public BlackboardArtifact getArtifact() { @@ -1812,6 +1832,13 @@ class ReportGenerator { return artifact.getObjectID(); } + /** + * @return the content + */ + public Content getContent() { + return content; + } + /** * Compares ArtifactData objects by the first attribute they have in * common in their List. Should only be used on two @@ -1881,8 +1908,8 @@ class ReportGenerator { List orderedRowData = new ArrayList<>(); if (ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == getArtifact().getArtifactTypeID()) { - AbstractFile file = skCase.getAbstractFileById(getObjectID()); - if (file != null) { + if (content != null && content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; orderedRowData.add(file.getName()); orderedRowData.add(file.getNameExtension()); String mimeType = file.getMIMEType(); @@ -1913,7 +1940,7 @@ class ReportGenerator { } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))) { String pathToShow = attr.getDisplayString(); if (pathToShow.isEmpty()) { - pathToShow = getFileUniquePath(getObjectID()); + pathToShow = getFileUniquePath(content); } attributeDataArray[2] = pathToShow; } @@ -1933,6 +1960,7 @@ class ReportGenerator { return orderedRowData; } + } /** @@ -1999,7 +2027,11 @@ class ReportGenerator { List attributes = artData.getAttributes(); for (BlackboardAttribute attribute : attributes) { if (attribute.getAttributeType().equals(this.attributeType)) { - return attribute.getDisplayString(); + if (attribute.getAttributeType().getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { + return attribute.getDisplayString(); + } else { + return ContentUtils.getStringTime(attribute.getValueLong(), artData.getContent()); + } } } return ""; @@ -2027,7 +2059,7 @@ class ReportGenerator { @Override public String getCellData(ArtifactData artData) { - return getFileUniquePath(artData.getObjectID()); + return getFileUniquePath(artData.getContent()); /*else if (this.columnHeader.equals(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))) { return makeCommaSeparatedList(artData.getTags()); } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 196f770ca7..eeca1efe56 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -560,15 +560,6 @@ class ReportHTML implements TableReportModule { return; } AbstractFile file = (AbstractFile) content; - - // Add metadata about the file to HTML output - row.add(file.getMtimeAsDate()); - row.add(file.getCtimeAsDate()); - row.add(file.getAtimeAsDate()); - row.add(file.getCrtimeAsDate()); - row.add(Long.toString(file.getSize())); - row.add(file.getMd5Hash()); - // Add the hyperlink to the row. A column header for it was created in startTable(). StringBuilder localFileLink = new StringBuilder(); // Don't make a local copy of the file if it is a directory or unallocated space. diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.form b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.form index b490520e46..597dd89df4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.form +++ b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.form @@ -29,11 +29,8 @@ - - - - - + + @@ -49,17 +46,17 @@ - + - + - + - - - + + + @@ -96,18 +93,7 @@ - - - - - - - - - - - - + @@ -122,5 +108,12 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java index e51a62de0e..59a7cb38b1 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,22 +19,32 @@ package org.sleuthkit.autopsy.report; import org.openide.util.NbBundle; - import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.io.File; import java.io.IOException; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +/** + * A panel used by a report generation module to show progress. + */ public class ReportProgressPanel extends javax.swing.JPanel { + private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(ReportProgressPanel.class.getName()); - private ReportStatus STATUS; + private static final Color GREEN = new Color(50, 205, 50); + private static final Color RED = new Color(178, 34, 34); + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private ReportStatus status; - // Enum to represent if a report is waiting, - // running, done, or has been canceled + /** + * Used by a report generation module to communicate report generation + * status to this panel and its listeners. + */ public enum ReportStatus { QUEUING, @@ -45,64 +55,60 @@ public class ReportProgressPanel extends javax.swing.JPanel { } /** - * Creates new form ReportProgressPanel + * Constructs a panel used by report generation module to show progress. + * + * @param reportName The name of the report being generated. + * @param reportPath The path to the report file. */ public ReportProgressPanel(String reportName, String reportPath) { initComponents(); - customInit(reportName, reportPath); - } - - private void customInit(String reportName, String reportPath) { reportProgressBar.setIndeterminate(true); reportProgressBar.setMaximum(100); - reportLabel.setText(reportName); - processingLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.progress.queuing")); - STATUS = ReportStatus.QUEUING; - - if (reportPath != null) { + statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.progress.queuing")); + status = ReportStatus.QUEUING; + if (null != reportPath) { pathLabel.setText("" + shortenPath(reportPath) + ""); //NON-NLS pathLabel.setToolTipText(reportPath); - - // Add the "link" effect to the pathLabel - final String linkPath = reportPath; + String linkPath = reportPath; pathLabel.addMouseListener(new MouseListener() { @Override - public void mouseClicked(MouseEvent e) { + public void mouseClicked(MouseEvent mouseEvent) { } @Override - public void mousePressed(MouseEvent e) { + public void mousePressed(MouseEvent mouseEvent) { } @Override - public void mouseReleased(MouseEvent e) { + public void mouseReleased(MouseEvent mouseEvent) { File file = new File(linkPath); try { Desktop.getDesktop().open(file); - } catch (IOException ex) { - } catch (IllegalArgumentException ex) { + } catch (IOException ioex) { + logger.log(Level.SEVERE, "Error opening report file", ioex); + } catch (IllegalArgumentException iaEx) { + logger.log(Level.SEVERE, "Error opening report file", iaEx); try { - // try to open the parent path if the file doens't exist Desktop.getDesktop().open(file.getParentFile()); - } catch (IOException ex1) { + } catch (IOException ioEx2) { + logger.log(Level.SEVERE, "Error opening report file parent", ioEx2); } } } @Override - public void mouseEntered(MouseEvent e) { + public void mouseEntered(MouseEvent e3) { pathLabel.setForeground(Color.DARK_GRAY); setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } @Override - public void mouseExited(MouseEvent e) { + public void mouseExited(MouseEvent e4) { pathLabel.setForeground(Color.BLACK); setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } - }); } else { pathLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.initPathLabel.noFile")); @@ -110,185 +116,196 @@ public class ReportProgressPanel extends javax.swing.JPanel { } /** - * Return a shortened version of the given path. + * Adds a property change listener to this panel. + * + * @param listener The listener to be added. */ - private String shortenPath(String path) { - if (path.length() > 100) { - path = path.substring(0, 10 + path.substring(10).indexOf(File.separator) + 1) + "..." - + path.substring((path.length() - 70) + path.substring(path.length() - 70).indexOf(File.separator)); - } - return path; + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + this.pcs.addPropertyChangeListener(listener); } /** - * Return the current ReportStatus of this report. + * Removes a property change listener from this panel. * - * @return ReportStatus status of this report + * @param listener The listener to be removed. + */ + @Override + public void removePropertyChangeListener(PropertyChangeListener listener) { + this.pcs.removePropertyChangeListener(listener); + } + + /** + * Gets the current status of the generation of the report. + * + * @return The report generation status as a ReportStatus enum. */ public ReportStatus getStatus() { - return STATUS; + return status; } /** - * Start the JProgressBar for this report. - * - * Enables the cancelButton, updates the processingLabel, and changes this - * report's ReportStatus. + * Starts the progress bar component of this panel. */ public void start() { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - processingLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.start.progress.text")); - STATUS = ReportStatus.RUNNING; - } + EventQueue.invokeLater(() -> { + statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.start.progress.text")); + status = ReportStatus.RUNNING; }); } /** - * Set the maximum progress for this report's JProgressBar. + * Sets the maximum value of the progress bar component of this panel. * - * @param max maximum progress for JProgressBar + * @param max The maximum value. */ - public void setMaximumProgress(final int max) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - if (STATUS != ReportStatus.CANCELED) { - reportProgressBar.setMaximum(max); - } + public void setMaximumProgress(int max) { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + reportProgressBar.setMaximum(max); } }); } /** - * Increment the JProgressBar for this report by one unit. + * Increments the current value of the progress bar component of this panel + * by one unit. */ public void increment() { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - if (STATUS != ReportStatus.CANCELED) { - reportProgressBar.setValue(reportProgressBar.getValue() + 1); - } + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + reportProgressBar.setValue(reportProgressBar.getValue() + 1); } }); } /** - * Set the value of the JProgressBar for this report. + * Sets the current value of the progress bar component of this panel. * - * @param value value to be set at + * @param value The value to be set. */ - public void setProgress(final int value) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - if (STATUS != ReportStatus.CANCELED) { - reportProgressBar.setValue(value); - } + public void setProgress(int value) { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + reportProgressBar.setValue(value); } }); } /** - * Changes the status of the JProgressBar to be determinate or + * Changes the the progress bar component of this panel to be determinate or * indeterminate. * - * @param indeterminate sets the JProgressBar to be indeterminate if true, - * determinate otherwise + * @param indeterminate True if the progress bar should be set to + * indeterminate. */ - public void setIndeterminate(final boolean indeterminate) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - if (STATUS != ReportStatus.CANCELED) { - reportProgressBar.setIndeterminate(indeterminate); - } + public void setIndeterminate(boolean indeterminate) { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + reportProgressBar.setIndeterminate(indeterminate); } }); } /** - * Change the text of this report's status label. The text given will be the - * full text used. e.g. updateStatusLabel("Now processing files...") sets - * the label to "Now processing files..." + * Changes the status message label component of this panel to show a given + * processing status message. For example, updateStatusLabel("Now processing + * files...") sets the label text to "Now processing files..." * - * @param status String to use as status + * @param statusMessage String to use as label text. */ - public void updateStatusLabel(final String status) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - if (STATUS != ReportStatus.CANCELED) { - processingLabel.setText(status); - } + public void updateStatusLabel(String statusMessage) { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + statusMessageLabel.setText(statusMessage); } }); } /** - * Declare the report completed. This will fill the JProgressBar, update the - * cancelButton to completed, and disallow any cancellation of this report. + * Makes the components of this panel indicate the final status of + * generation of the report. * - * @deprecated Use {@link #complete(ReportStatus)} - */ - @Deprecated - public void complete() { - complete(ReportStatus.COMPLETE); - } - - /** - * Declare the report completed ands sets if completed successfully or with - * errors. This will fill the JProgressBar, update the cancelButton to - * completed, and disallow any cancellation of this report. - * - * @param reportStatus set to appropriate ResultStatus enum. + * @param reportStatus The final status, must be COMPLETE or ERROR. */ public void complete(ReportStatus reportStatus) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - // make sure we disable an indeterminate - reportProgressBar.setIndeterminate(false); - - if (STATUS != ReportStatus.CANCELED) { - switch (reportStatus) { - case COMPLETE: { - STATUS = ReportStatus.COMPLETE; - processingLabel.setForeground(Color.BLACK); - processingLabel.setText( - NbBundle.getMessage(this.getClass(), "ReportProgressPanel.complete.processLbl.text")); - reportProgressBar.setValue(reportProgressBar.getMaximum()); - reportProgressBar.setStringPainted(true); - // set reportProgressBar color as green. - reportProgressBar.setForeground(new Color(50, 205, 50)); - reportProgressBar.setString("Complete"); //NON-NLS - - break; - } - case ERROR: { - STATUS = ReportStatus.ERROR; - processingLabel.setForeground(new Color(178, 34, 34)); - processingLabel.setText( - NbBundle.getMessage(this.getClass(), "ReportProgressPanel.complete.processLb2.text")); - reportProgressBar.setValue(reportProgressBar.getMaximum()); - reportProgressBar.setStringPainted(true); - // set reportProgressBar color as red. - reportProgressBar.setForeground(new Color(178, 34, 34)); - reportProgressBar.setString("Error"); //NON-NLS - break; - } - // add finer grained result codes here. - default: { - logger.log(Level.SEVERE, "Invalid ReportStatus code {0}", reportStatus); //NON-NLS - break; - } + EventQueue.invokeLater(() -> { + reportProgressBar.setIndeterminate(false); + if (status != ReportStatus.CANCELED) { + switch (reportStatus) { + case COMPLETE: { + ReportStatus oldValue = status; + status = ReportStatus.COMPLETE; + statusMessageLabel.setForeground(Color.BLACK); + statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.complete.processLbl.text")); + reportProgressBar.setValue(reportProgressBar.getMaximum()); + reportProgressBar.setStringPainted(true); + reportProgressBar.setForeground(GREEN); + reportProgressBar.setString("Complete"); //NON-NLS + pcs.firePropertyChange(ReportStatus.COMPLETE.toString(), oldValue, status); + break; + } + case ERROR: { + ReportStatus oldValue = status; + status = ReportStatus.ERROR; + statusMessageLabel.setForeground(RED); + statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.complete.processLb2.text")); + reportProgressBar.setValue(reportProgressBar.getMaximum()); + reportProgressBar.setStringPainted(true); + reportProgressBar.setForeground(RED); + reportProgressBar.setString("Error"); //NON-NLS + pcs.firePropertyChange(ReportStatus.COMPLETE.toString(), oldValue, status); + break; + } + default: { + break; } } } }); - // Do something with the button to change the icon and make not clickable + } + + /** + * Makes the components of this panel indicate generation of the report was + * cancelled. + */ + void cancel() { + switch (status) { + case COMPLETE: + break; + case CANCELED: + break; + case ERROR: + break; + default: + ReportStatus oldValue = status; + status = ReportStatus.CANCELED; + reportProgressBar.setIndeterminate(false); + reportProgressBar.setValue(0); + reportProgressBar.setStringPainted(true); + reportProgressBar.setForeground(RED); // Red + reportProgressBar.setString("Cancelled"); //NON-NLS + pcs.firePropertyChange(ReportStatus.CANCELED.toString(), oldValue, status); + statusMessageLabel.setForeground(RED); + statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.cancel.procLbl.text")); + break; + } + } + + /** + * Gets a shortened version of a file path. + * + * @param path The path to shorten. + * + * @return The shortened path. + */ + private String shortenPath(String path) { + if (path.length() > 100) { + return path.substring(0, 10 + path.substring(10).indexOf(File.separator) + 1) + "..." + + path.substring((path.length() - 70) + path.substring(path.length() - 70).indexOf(File.separator)); + } else { + return path; + } } /** @@ -303,8 +320,8 @@ public class ReportProgressPanel extends javax.swing.JPanel { reportProgressBar = new javax.swing.JProgressBar(); reportLabel = new javax.swing.JLabel(); pathLabel = new javax.swing.JLabel(); - processingLabel = new javax.swing.JLabel(); separationLabel = new javax.swing.JLabel(); + statusMessageLabel = new javax.swing.JLabel(); setFont(getFont().deriveFont(getFont().getStyle() & ~java.awt.Font.BOLD, 11)); setMinimumSize(new java.awt.Dimension(486, 68)); @@ -316,13 +333,13 @@ public class ReportProgressPanel extends javax.swing.JPanel { pathLabel.setFont(pathLabel.getFont().deriveFont(pathLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ReportProgressPanel.class, "ReportProgressPanel.pathLabel.text")); // NOI18N - - processingLabel.setFont(processingLabel.getFont().deriveFont((processingLabel.getFont().getStyle() | java.awt.Font.ITALIC) & ~java.awt.Font.BOLD, 10)); - org.openide.awt.Mnemonics.setLocalizedText(processingLabel, org.openide.util.NbBundle.getMessage(ReportProgressPanel.class, "ReportProgressPanel.processingLabel.text")); // NOI18N + pathLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); separationLabel.setFont(separationLabel.getFont().deriveFont(separationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(separationLabel, org.openide.util.NbBundle.getMessage(ReportProgressPanel.class, "ReportProgressPanel.separationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(statusMessageLabel, org.openide.util.NbBundle.getMessage(ReportProgressPanel.class, "ReportProgressPanel.statusMessageLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -330,10 +347,8 @@ public class ReportProgressPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(processingLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(reportProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(58, 58, 58)) + .addComponent(statusMessageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(reportProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(reportLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -350,45 +365,32 @@ public class ReportProgressPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(reportLabel) - .addComponent(pathLabel) + .addComponent(pathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(separationLabel)) - .addGap(0, 0, 0) - .addComponent(processingLabel) - .addContainerGap(20, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(statusMessageLabel) + .addGap(13, 13, 13)) ); }// //GEN-END:initComponents - /** - * Cancels the current report, based on it's status. If the report is - * complete or has already been completed, nothing happens. - */ - void cancel() { - switch (STATUS) { - case COMPLETE: - break; - case CANCELED: - break; - case ERROR: - break; - default: - STATUS = ReportStatus.CANCELED; - reportProgressBar.setIndeterminate(false); - reportProgressBar.setValue(0); - reportProgressBar.setStringPainted(true); - // set reportProgressBar color as red. - reportProgressBar.setForeground(new Color(178, 34, 34)); - reportProgressBar.setString("Cancelled"); //NON-NLS - processingLabel.setForeground(new Color(178, 34, 34)); - processingLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.cancel.procLbl.text")); - break; - } - } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel pathLabel; - private javax.swing.JLabel processingLabel; private javax.swing.JLabel reportLabel; private javax.swing.JProgressBar reportProgressBar; private javax.swing.JLabel separationLabel; + private javax.swing.JLabel statusMessageLabel; // End of variables declaration//GEN-END:variables + + /** + * Makes the components of this panel indicate the generation of the report + * is completed. + * + * @deprecated Use {@link #complete(ReportStatus)} + */ + @Deprecated + public void complete() { + complete(ReportStatus.COMPLETE); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/Bundle.properties b/Core/src/org/sleuthkit/autopsy/timeline/Bundle.properties index 9f2e0c950c..131934652e 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/timeline/Bundle.properties @@ -1,4 +1,4 @@ -CTL_MakeTimeline="Timeline" +CTL_MakeTimeline=Timeline CTL_TimeLineTopComponentAction=TimeLineTopComponent CTL_TimeLineTopComponent=Timeline Window HINT_TimeLineTopComponent=This is a Timeline window @@ -24,7 +24,5 @@ TimelinePanel.jButton7.text=3d TimelinePanel.jButton2.text=1m TimelinePanel.jButton3.text=3m TimelinePanel.jButton4.text=2w -OpenTimelineAction.title=Timeline -OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources. ProgressWindow.progressHeader.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java index 78b21bd9e8..b766394926 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,8 +18,8 @@ */ package org.sleuthkit.autopsy.timeline; +import java.io.IOException; import java.util.logging.Level; -import javax.swing.JOptionPane; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -27,10 +27,10 @@ import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; -import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline") @@ -58,35 +58,39 @@ public class OpenTimelineAction extends CallableSystemAction { return Case.isCaseOpen() && fxInited;// && Case.getCurrentCase().hasData(); } + @NbBundle.Messages({ + "OpenTimelineAction.settingsErrorMessage=Failed to initialize timeline settings.", + "OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources."}) @Override @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void performAction() { - //check case - if (!Case.isCaseOpen()) { - return; + try { + Case currentCase = Case.getCurrentCase(); + if (currentCase.hasData() == false) { + MessageNotifyUtil.Message.info(Bundle.OpenTimeLineAction_msgdlg_text()); + LOGGER.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS + return; + } + try { + if (timeLineController == null) { + timeLineController = new TimeLineController(currentCase); + } else if (timeLineController.getAutopsyCase() != currentCase) { + timeLineController.shutDownTimeLine(); + timeLineController = new TimeLineController(currentCase); + } + timeLineController.openTimeLine(); + } catch (IOException iOException) { + MessageNotifyUtil.Message.error(Bundle.OpenTimelineAction_settingsErrorMessage()); + LOGGER.log(Level.SEVERE, "Failed to initialize per case timeline settings.", iOException); + } + } catch (IllegalStateException e) { + //there is no case... Do nothing. } - final Case currentCase = Case.getCurrentCase(); - - if (currentCase.hasData() == false) { - JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), - NbBundle.getMessage(this.getClass(), "OpenTimeLineAction.msgdlg.text")); - LOGGER.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS - return; - } - - if (timeLineController == null) { - timeLineController = new TimeLineController(currentCase); - } else if (timeLineController.getAutopsyCase() != currentCase) { - timeLineController.closeTimeLine(); - timeLineController = new TimeLineController(currentCase); - } - - timeLineController.openTimeLine(); } @Override public String getName() { - return NbBundle.getMessage(TimeLineTopComponent.class, "OpenTimelineAction.title"); + return NbBundle.getMessage(OpenTimelineAction.class, "CTL_MakeTimeline"); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/timeline/PerCaseTimelineProperties.java b/Core/src/org/sleuthkit/autopsy/timeline/PerCaseTimelineProperties.java new file mode 100644 index 0000000000..6861dac340 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/timeline/PerCaseTimelineProperties.java @@ -0,0 +1,177 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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.timeline; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.Properties; +import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.casemodule.Case; + +/** + * Provides access to per-case timeline properties (key-value store). + */ +class PerCaseTimelineProperties { + + private static final String STALE_KEY = "stale"; //NON-NLS + private static final String WAS_INGEST_RUNNING_KEY = "was_ingest_running"; // NON-NLS + + private final Case autoCase; + private final Path propertiesPath; + + PerCaseTimelineProperties(Case c) { + Objects.requireNonNull(c, "Case must not be null"); + this.autoCase = c; + propertiesPath = Paths.get(autoCase.getModuleDirectory(), "Timeline", "timeline.properties"); //NON-NLS + } + + /** + * Is the DB stale, i.e. does it need to be updated because new datasources + * (eg) have been added to the case. + * + * @return true if the db is stale + * + * @throws IOException if there is a problem reading the state from disk + */ + public synchronized boolean isDBStale() throws IOException { + + String stale = getProperty(STALE_KEY); + return StringUtils.isBlank(stale) ? true : Boolean.valueOf(stale); + + } + + /** + * record the state of the events db as stale(true) or not stale(false). + * + * @param stale the new state of the event db. true for stale, false for not + * stale. + * + * @throws IOException if there was a problem writing the state to disk. + */ + public synchronized void setDbStale(Boolean stale) throws IOException { + setProperty(STALE_KEY, stale.toString()); + } + + /** + * Was ingest running the last time the database was updated? + * + * @return true if ingest was running the last time the db was updated + * + * @throws IOException if there was a problem reading from disk + */ + public synchronized boolean wasIngestRunning() throws IOException { + String stale = getProperty(WAS_INGEST_RUNNING_KEY); + return StringUtils.isBlank(stale) ? true : Boolean.valueOf(stale); + } + + /** + * record whether ingest was running during the last time the database was + * updated + * + * @param ingestRunning true if ingest was running + * + * @throws IOException if there was a problem writing to disk + */ + public synchronized void setIngestRunning(Boolean ingestRunning) throws IOException { + setProperty(WAS_INGEST_RUNNING_KEY, ingestRunning.toString()); + } + + /** + * Get a {@link Path} to the properties file. If the file does not exist, it + * will be created. + * + * @return the Path to the properties file. + * + * @throws IOException if there was a problem creating the properties file + */ + private synchronized Path getPropertiesPath() throws IOException { + + if (!Files.exists(propertiesPath)) { + Path parent = propertiesPath.getParent(); + Files.createDirectories(parent); + Files.createFile(propertiesPath); + } + return propertiesPath; + } + + /** + * Returns the property with the given key. + * + * @param propertyKey - The property key to get the value for. + * + * @return - the value associated with the property. + * + * @throws IOException if there was a problem reading the property from disk + */ + private synchronized String getProperty(String propertyKey) throws IOException { + return getProperties().getProperty(propertyKey); + } + + /** + * Sets the given property to the given value. + * + * @param propertyKey - The key of the property to be modified. + * @param propertyValue - the value to set the property to. + * + * @throws IOException if there was a problem writing the property to disk + */ + private synchronized void setProperty(String propertyKey, String propertyValue) throws IOException { + Path propertiesFile = getPropertiesPath(); + Properties props = getProperties(propertiesFile); + props.setProperty(propertyKey, propertyValue); + + try (OutputStream fos = Files.newOutputStream(propertiesFile)) { + props.store(fos, ""); //NON-NLS + } + } + + /** + * Get a {@link Properties} object used to store the timeline properties. + * + * @return a properties object + * + * @throws IOException if there was a problem reading the .properties file + */ + private synchronized Properties getProperties() throws IOException { + return getProperties(getPropertiesPath()); + } + + /** + * Gets a {@link Properties} object populated form the given .properties + * file. + * + * @param propertiesFile a path to the .properties file to load + * + * @return a properties object + * + * @throws IOException if there was a problem reading the .properties file + */ + private synchronized Properties getProperties(final Path propertiesFile) throws IOException { + try (InputStream inputStream = Files.newInputStream(propertiesFile)) { + Properties props = new Properties(); + props.load(inputStream); + return props; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java b/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java index 131b8db003..893ff1dec4 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.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"); @@ -61,9 +61,9 @@ public class PromptDialogManager { static { Image x = null; try { - x = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream()); //NOI18N + x = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream()); //NON-NLS } catch (IOException ex) { - LOGGER.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex); //NOI18N NON-NLS + LOGGER.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex); //NON-NLS } LOGO = x; } @@ -75,6 +75,12 @@ public class PromptDialogManager { this.controller = controller; } + /** + * bring the currently managed dialog (if there is one) to the front + * + * @return true if a dialog was brought to the front, or false of there is + * no currently managed open dialog + */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean bringCurrentDialogToFront() { if (currentDialog != null && currentDialog.isShowing()) { @@ -86,11 +92,12 @@ public class PromptDialogManager { @NbBundle.Messages({"PromptDialogManager.progressDialog.title=Populating Timeline Data"}) @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - public void showProgressDialog(CancellationProgressTask task) { + void showProgressDialog(CancellationProgressTask task) { currentDialog = new ProgressDialog(task); - currentDialog.headerTextProperty().bind(task.titleProperty()); - setDialogIcons(currentDialog); + currentDialog.initModality(Modality.NONE); currentDialog.setTitle(Bundle.PromptDialogManager_progressDialog_title()); + setDialogIcons(currentDialog); + currentDialog.headerTextProperty().bind(task.titleProperty()); DialogPane dialogPane = currentDialog.getDialogPane(); dialogPane.setPrefSize(400, 200); //override autosizing which fails for some reason @@ -98,6 +105,8 @@ public class PromptDialogManager { //co-ordinate task cancelation and dialog hiding. task.setOnCancelled(cancelled -> currentDialog.close()); task.setOnSucceeded(succeeded -> currentDialog.close()); + task.setOnFailed(failed -> currentDialog.close()); + dialogPane.getButtonTypes().setAll(ButtonType.CANCEL); final Node cancelButton = dialogPane.lookupButton(ButtonType.CANCEL); cancelButton.disableProperty().bind(task.cancellableProperty().not()); @@ -115,14 +124,7 @@ public class PromptDialogManager { @ThreadConfined(type = ThreadConfined.ThreadType.JFX) static private void setDialogIcons(Dialog dialog) { - Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow(); - stage.getIcons().setAll(LOGO); - } - - @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - static private void setDialogTitle(Dialog dialog) { - Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow(); - stage.setTitle(Bundle.Timeline_confirmation_dialogs_title()); + ((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().setAll(LOGO); } /** @@ -139,7 +141,7 @@ public class PromptDialogManager { currentDialog.initModality(Modality.APPLICATION_MODAL); currentDialog.setHeaderText(Bundle.PromptDialogManager_confirmDuringIngest_headerText()); setDialogIcons(currentDialog); - setDialogTitle(currentDialog); + currentDialog.setTitle(Bundle.Timeline_confirmation_dialogs_title()); return currentDialog.showAndWait().map(SHOW_TIMELINE::equals).orElse(false); } @@ -152,7 +154,7 @@ public class PromptDialogManager { currentDialog.initModality(Modality.APPLICATION_MODAL); currentDialog.setHeaderText(Bundle.PromptDialogManager_rebuildPrompt_headerText()); setDialogIcons(currentDialog); - setDialogTitle(currentDialog); + currentDialog.setTitle(Bundle.Timeline_confirmation_dialogs_title()); DialogPane dialogPane = currentDialog.getDialogPane(); ListView listView = new ListView<>(FXCollections.observableArrayList(rebuildReasons)); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java index a33bdb50d1..c77ba8ee75 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-2015 Basis Technology Corp. + * Copyright 2014-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,7 @@ package org.sleuthkit.autopsy.timeline; import java.awt.HeadlessException; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.io.IOException; import java.time.ZoneId; import java.util.ArrayList; import java.util.Collection; @@ -31,9 +30,10 @@ import java.util.TimeZone; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.logging.Level; import javafx.application.Platform; -import javafx.beans.InvalidationListener; import javafx.beans.Observable; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; @@ -49,7 +49,6 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.concurrent.Task; import javafx.concurrent.Worker; -import javafx.scene.control.Dialog; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.Immutable; import javax.swing.SwingUtilities; @@ -83,9 +82,6 @@ import org.sleuthkit.autopsy.timeline.utils.IntervalUtils; import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD; import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel; import org.sleuthkit.autopsy.timeline.zooming.ZoomParams; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; -import org.sleuthkit.datamodel.TskCoreException; /** * Controller in the MVC design along with model = {@link FilteredEventsModel} @@ -139,9 +135,6 @@ public class TimeLineController { private final ReadOnlyStringWrapper status = new ReadOnlyStringWrapper(); - @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - private Dialog currentDialog; - /** * status is a string that will be displayed in the status bar as a kind of * user hint/information when it is not empty @@ -156,12 +149,13 @@ public class TimeLineController { status.set(string); } private final Case autoCase; + private final PerCaseTimelineProperties perCaseTimelineProperties; @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - private final ObservableList quickHideMaskFilters = FXCollections.observableArrayList(); + private final ObservableList quickHideFilters = FXCollections.observableArrayList(); public ObservableList getQuickHideFilters() { - return quickHideMaskFilters; + return quickHideFilters; } /** @@ -219,13 +213,12 @@ public class TimeLineController { @GuardedBy("this") private final ReadOnlyObjectWrapper currentParams = new ReadOnlyObjectWrapper<>(); - //all members should be access with the intrinsict lock of this object held //selected events (ie shown in the result viewer) @GuardedBy("this") private final ObservableList selectedEventIDs = FXCollections.synchronizedObservableList(FXCollections.observableArrayList()); /** - * @return an unmodifiable list of the selected event ids + * @return a list of the selected event ids */ synchronized public ObservableList getSelectedEventIDs() { return selectedEventIDs; @@ -241,14 +234,8 @@ public class TimeLineController { return selectedTimeRange.getReadOnlyProperty(); } - public ReadOnlyBooleanProperty getNewEventsFlag() { - return newEventsFlag.getReadOnlyProperty(); - } - - private final ReadOnlyBooleanWrapper needsHistogramRebuild = new ReadOnlyBooleanWrapper(false); - - public ReadOnlyBooleanProperty getNeedsHistogramRebuild() { - return needsHistogramRebuild.getReadOnlyProperty(); + public ReadOnlyBooleanProperty eventsDBStaleProperty() { + return eventsDBStale.getReadOnlyProperty(); } synchronized public ReadOnlyBooleanProperty getCanAdvance() { @@ -258,28 +245,26 @@ public class TimeLineController { synchronized public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - private final ReadOnlyBooleanWrapper newEventsFlag = new ReadOnlyBooleanWrapper(false); + private final ReadOnlyBooleanWrapper eventsDBStale = new ReadOnlyBooleanWrapper(true); private final PromptDialogManager promptDialogManager = new PromptDialogManager(this); - public TimeLineController(Case autoCase) { + public TimeLineController(Case autoCase) throws IOException { this.autoCase = autoCase; - + this.perCaseTimelineProperties = new PerCaseTimelineProperties(autoCase); + eventsDBStale.set(perCaseTimelineProperties.isDBStale()); + eventsRepository = new EventsRepository(autoCase, currentParams.getReadOnlyProperty()); /* * as the history manager's current state changes, modify the tags * filter to be in sync, and expose that as propery from * TimeLineController. Do we need to do this with datasource or hash hit * filters? */ - historyManager.currentState().addListener(new InvalidationListener() { - public void invalidated(Observable observable) { - ZoomParams historyManagerParams = historyManager.getCurrentState(); - eventsRepository.syncTagsFilter(historyManagerParams.getFilter().getTagsFilter()); - currentParams.set(historyManagerParams); - } + historyManager.currentState().addListener((Observable observable) -> { + ZoomParams historyManagerParams = historyManager.getCurrentState(); + eventsRepository.syncTagsFilter(historyManagerParams.getFilter().getTagsFilter()); + currentParams.set(historyManagerParams); }); - - eventsRepository = new EventsRepository(autoCase, currentParams.getReadOnlyProperty()); filteredEvents = eventsRepository.getEventsModel(); InitialZoomState = new ZoomParams(filteredEvents.getSpanningInterval(), @@ -306,54 +291,52 @@ public class TimeLineController { } /** - * rebuld the repo. + * rebuild the repo using the given repo builder (expected to be a member + * reference to {@link EventsRepository#rebuildRepository(java.util.function.Consumer) + * } or {@link EventsRepository#rebuildTags(java.util.function.Consumer) }) + * and display the ui when it is done. * - * @return False if the repo was not rebuilt because because the user - * aborted after prompt about ingest running. True if the repo was - * rebuilt. + * @param repoBuilder */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - void rebuildRepo() { + private void rebuildRepoHelper(Function, CancellationProgressTask> repoBuilder) { SwingUtilities.invokeLater(this::closeTimelineWindow); - final CancellationProgressTask rebuildRepository = eventsRepository.rebuildRepository(); - rebuildRepository.stateProperty().addListener((stateProperty, oldState, newSate) -> { + boolean ingestRunning = IngestManager.getInstance().isIngestRunning(); + final CancellationProgressTask rebuildRepository = repoBuilder.apply(newSate -> { + setIngestRunning(ingestRunning); //this will be on JFX thread - if (newSate == Worker.State.SUCCEEDED) { - //TODO: this looks hacky. what is going on? should this be an event? - needsHistogramRebuild.set(true); - needsHistogramRebuild.set(false); - SwingUtilities.invokeLater(TimeLineController.this::showWindow); - - //TODO: should this be an event? - newEventsFlag.set(false); - historyManager.reset(filteredEvents.zoomParametersProperty().get()); - TimeLineController.this.showFullRange(); - + switch (newSate) { + case SUCCEEDED: + setEventsDBStale(false); + SwingUtilities.invokeLater(TimeLineController.this::showWindow); + historyManager.reset(filteredEvents.zoomParametersProperty().get()); + TimeLineController.this.showFullRange(); + break; + case FAILED: + case CANCELLED: + setEventsDBStale(true); + break; } }); promptDialogManager.showProgressDialog(rebuildRepository); + } + /** + * rebuld the entire repo. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) + void rebuildRepo() { + rebuildRepoHelper(eventsRepository::rebuildRepository); } /** * Since tags might have changed while TimeLine wasn't listening, drop the * tags table and rebuild it by querying for all the tags and inserting them * in to the TimeLine DB. - * */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) void rebuildTagsTable() { - - SwingUtilities.invokeLater(this::closeTimelineWindow); - CancellationProgressTask rebuildTags = eventsRepository.rebuildTags(); - rebuildTags.stateProperty().addListener((stateProperty, oldState, newSate) -> { - //this will be on JFX thread - if (newSate == Worker.State.SUCCEEDED) { - SwingUtilities.invokeLater(TimeLineController.this::showWindow); - showFullRange(); - } - }); - promptDialogManager.showProgressDialog(rebuildTags); + rebuildRepoHelper(eventsRepository::rebuildTags); } @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @@ -370,7 +353,7 @@ public class TimeLineController { } @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - public void closeTimeLine() { + public void shutDownTimeLine() { if (mainFrame != null) { listeningToAutopsy = false; IngestManager.getInstance().removeIngestModuleEventListener(ingestModuleListener); @@ -409,7 +392,7 @@ public class TimeLineController { /* * if the repo was not rebuilt at minimum rebuild the tags which * may have been updated without our knowing it, since we - * can't/aren't checking them. This should at elast be quick. + * can't/aren't checking them. This should at least be quick. * //TODO: can we check the tags to see if we need to do this? */ if (checkAndPromptForRebuild() == false) { @@ -425,7 +408,7 @@ public class TimeLineController { @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private boolean checkAndPromptForRebuild() { //if the repo is empty just (r)ebuild it with out asking, they can always cancel part way through; - if (eventsRepository.getLastObjID() == -1) { + if (eventsRepository.countAllEvents() == 0) { rebuildRepo(); return true; } @@ -440,7 +423,6 @@ public class TimeLineController { return false; } - @SuppressWarnings("deprecation") // TODO (EUR-733): Do not use SleuthkitCase.getLastObjectId @ThreadConfined(type = ThreadConfined.ThreadType.ANY) @NbBundle.Messages({"TimeLineController.errorTitle=Timeline error.", "TimeLineController.outOfDate.errorMessage=Error determing if the timeline is out of date. We will assume it should be updated. See the logs for more details.", @@ -450,23 +432,23 @@ public class TimeLineController { "TimeLineController.rebuildReasons.incompleteOldSchema=The Timeline events database was previously populated without incomplete information: Some features may be unavailable or non-functional unless you update the events database."}) private ArrayList getRebuildReasons() { ArrayList rebuildReasons = new ArrayList<>(); - //if ingest was running during last rebuild, prompt to rebuild - if (eventsRepository.getWasIngestRunning()) { - rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_ingestWasRunning()); - } - final SleuthkitCase sleuthkitCase = autoCase.getSleuthkitCase(); + try { - //if the last artifact and object ids don't match between skc and tldb, prompt to rebuild - if (sleuthkitCase.getLastObjectId() != eventsRepository.getLastObjID() - || getCaseLastArtifactID(sleuthkitCase) != eventsRepository.getLastArtfactID()) { - rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDate()); + //if ingest was running during last rebuild, prompt to rebuild + if (perCaseTimelineProperties.wasIngestRunning()) { + rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_ingestWasRunning()); } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error determing last object id from sleutkit case. We will assume the timeline is out of date.", ex); // NON-NLS + + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, "Error determing the state of the timeline db. We will assume the it is out of date.", ex); // NON-NLS MessageNotifyUtil.Notify.error(Bundle.TimeLineController_errorTitle(), Bundle.TimeLineController_outOfDate_errorMessage()); rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDateError()); } + //if the events db is stale, prompt to rebuild + if (isEventsDBStale()) { + rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDate()); + } // if the TLDB schema has been upgraded since last time TL ran, prompt for rebuild if (eventsRepository.hasNewColumns() == false) { rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_incompleteOldSchema()); @@ -474,21 +456,6 @@ public class TimeLineController { return rebuildReasons; } - public static long getCaseLastArtifactID(final SleuthkitCase sleuthkitCase) { - //TODO: push this into sleuthkitCase - long caseLastArtfId = -1; - String query = "select Max(artifact_id) as max_id from blackboard_artifacts"; // NON-NLS //NOI18N - try (CaseDbQuery dbQuery = sleuthkitCase.executeQuery(query)) { - ResultSet resultSet = dbQuery.getResultSet(); - while (resultSet.next()) { - caseLastArtfId = resultSet.getLong("max_id"); // NON-NLS //NOI18N - } - } catch (TskCoreException | SQLException ex) { - LOGGER.log(Level.SEVERE, "Error getting last artifact id: ", ex); // NON-NLS //NOI18N - } - return caseLastArtfId; - } - /** * request a time range the same length as the given period and centered * around the middle of the currently selected range @@ -752,6 +719,38 @@ public class TimeLineController { } } + /** + * is the events db out of date + * + * @return true if the events db is out of date , false otherwise + */ + public boolean isEventsDBStale() { + return eventsDBStale.get(); + } + + /** + * + * @param stale the value of stale + */ + private void setEventsDBStale(final Boolean stale) { + eventsDBStale.set(stale); + try { + perCaseTimelineProperties.setDbStale(stale); + } catch (IOException ex) { + MessageNotifyUtil.Notify.error("Timeline", "Failed to mark the timeline db as " + (stale ? "" : "not ") + "stale. Some results may be out of date or missing."); + LOGGER.log(Level.SEVERE, "Error marking the timeline db as stale.", ex); + } + } + + private void setIngestRunning(boolean ingestRunning) { + try { + perCaseTimelineProperties.setIngestRunning(ingestRunning); + } catch (IOException ex) { + MessageNotifyUtil.Notify.error("Timeline", "Failed to mark the timeline db as populated while ingest was" + (ingestRunning ? "" : "not ") + "running. Some results may be out of date or missing."); + LOGGER.log(Level.SEVERE, "Error marking the ingest state while the timeline db was populated.", ex); + } + } + private class AutopsyIngestModuleListener implements PropertyChangeListener { @Override @@ -773,12 +772,10 @@ public class TimeLineController { switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) { case CONTENT_CHANGED: - case DATA_ADDED: break; + case DATA_ADDED: case FILE_DONE: - Platform.runLater(() -> { - newEventsFlag.set(true); - }); + Platform.runLater(() -> setEventsDBStale(true)); break; } } @@ -804,32 +801,26 @@ public class TimeLineController { public void propertyChange(PropertyChangeEvent evt) { switch (Case.Events.valueOf(evt.getPropertyName())) { case BLACKBOARD_ARTIFACT_TAG_ADDED: - executor.submit(() -> { - filteredEvents.handleArtifactTagAdded((BlackBoardArtifactTagAddedEvent) evt); - }); + executor.submit(() -> filteredEvents.handleArtifactTagAdded((BlackBoardArtifactTagAddedEvent) evt)); break; case BLACKBOARD_ARTIFACT_TAG_DELETED: - executor.submit(() -> { - filteredEvents.handleArtifactTagDeleted((BlackBoardArtifactTagDeletedEvent) evt); - }); + executor.submit(() -> filteredEvents.handleArtifactTagDeleted((BlackBoardArtifactTagDeletedEvent) evt)); break; case CONTENT_TAG_ADDED: - executor.submit(() -> { - filteredEvents.handleContentTagAdded((ContentTagAddedEvent) evt); - }); + executor.submit(() -> filteredEvents.handleContentTagAdded((ContentTagAddedEvent) evt)); break; case CONTENT_TAG_DELETED: - executor.submit(() -> { - filteredEvents.handleContentTagDeleted((ContentTagDeletedEvent) evt); - }); + executor.submit(() -> filteredEvents.handleContentTagDeleted((ContentTagDeletedEvent) evt)); break; case DATA_SOURCE_ADDED: - SwingUtilities.invokeLater(TimeLineController.this::confirmOutOfDateRebuildIfWindowOpen); + Platform.runLater(() -> { + setEventsDBStale(true); + SwingUtilities.invokeLater(TimeLineController.this::confirmOutOfDateRebuildIfWindowOpen); + }); break; - case CURRENT_CASE: OpenTimelineAction.invalidateController(); - SwingUtilities.invokeLater(TimeLineController.this::closeTimeLine); + SwingUtilities.invokeLater(TimeLineController.this::shutDownTimeLine); break; } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/MiscTypes.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/MiscTypes.java index 3d73982bf5..ce7f009ceb 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/MiscTypes.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/MiscTypes.java @@ -42,7 +42,7 @@ import org.sleuthkit.datamodel.TskCoreException; public enum MiscTypes implements EventType, ArtifactEventType { MESSAGE(NbBundle.getMessage(MiscTypes.class, "MiscTypes.message.name"), "message.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_MESSAGE), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_MESSAGE), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE)), artf -> { @@ -56,7 +56,7 @@ public enum MiscTypes implements EventType, ArtifactEventType { }, new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TEXT))), GPS_ROUTE(NbBundle.getMessage(MiscTypes.class, "MiscTypes.GPSRoutes.name"), "gps-search.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_GPS_ROUTE), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_GPS_ROUTE), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME)), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION)), @@ -68,7 +68,7 @@ public enum MiscTypes implements EventType, ArtifactEventType { return String.format("from %1$s %2$s to %3$s %4$s", stringValueOf(latStart), stringValueOf(longStart), stringValueOf(latEnd), stringValueOf(longEnd)); // NON-NLS }), GPS_TRACKPOINT(NbBundle.getMessage(MiscTypes.class, "MiscTypes.GPSTrackpoint.name"), "gps-trackpoint.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_GPS_TRACKPOINT), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_GPS_TRACKPOINT), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME)), artf -> { @@ -78,13 +78,13 @@ public enum MiscTypes implements EventType, ArtifactEventType { }, EMPTY_EXTRACTOR), CALL_LOG(NbBundle.getMessage(MiscTypes.class, "MiscTypes.Calls.name"), "calllog.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_CALLLOG), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_CALLLOG), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_START), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME)), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DIRECTION))), EMAIL(NbBundle.getMessage(MiscTypes.class, "MiscTypes.Email.name"), "mail-icon-16.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_EMAIL_MSG), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_EMAIL_MSG), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_SENT), artf -> { final BlackboardAttribute emailFrom = getAttributeSafe(artf, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_FROM)); @@ -94,7 +94,7 @@ public enum MiscTypes implements EventType, ArtifactEventType { new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SUBJECT)), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN))), RECENT_DOCUMENTS(NbBundle.getMessage(MiscTypes.class, "MiscTypes.recentDocuments.name"), "recent_docs.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_RECENT_OBJECT), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_RECENT_OBJECT), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH)).andThen( (String t) -> (StringUtils.substringBeforeLast(StringUtils.substringBeforeLast(t, "\\"), "\\"))), @@ -117,13 +117,13 @@ public enum MiscTypes implements EventType, ArtifactEventType { } }, INSTALLED_PROGRAM(NbBundle.getMessage(MiscTypes.class, "MiscTypes.installedPrograms.name"), "programs.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_INSTALLED_PROG), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_INSTALLED_PROG), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME)), EMPTY_EXTRACTOR, EMPTY_EXTRACTOR), EXIF(NbBundle.getMessage(MiscTypes.class, "MiscTypes.exif.name"), "camera-icon-16.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_METADATA_EXIF), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_METADATA_EXIF), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE)), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL)), @@ -139,7 +139,7 @@ public enum MiscTypes implements EventType, ArtifactEventType { return "error loading file name"; }), DEVICES_ATTACHED(NbBundle.getMessage(MiscTypes.class, "MiscTypes.devicesAttached.name"), "usb_devices.png", // NON-NLS - TypeUtils.fromEnum(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED), + new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED), new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE)), new AttributeExtractor(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL)), diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/TypeUtils.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/TypeUtils.java deleted file mode 100644 index 889511f037..0000000000 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/TypeUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 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.timeline.datamodel.eventtype; - -import org.sleuthkit.datamodel.BlackboardArtifact; - -/** - * - */ -class TypeUtils { - -//TODO: this will be unncessary once their is BlackboardArtifact.Type constructr that takes a BlackboardArtifact.ARTIFACT_TYPE - static BlackboardArtifact.Type fromEnum(BlackboardArtifact.ARTIFACT_TYPE type) { - return new BlackboardArtifact.Type(type.getTypeID(), type.getLabel(), type.getDisplayName()); - } - - private TypeUtils() { - } -} diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/WebTypes.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/WebTypes.java index 2bb3b92ef4..33cbe4836c 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/WebTypes.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/eventtype/WebTypes.java @@ -37,7 +37,7 @@ public enum WebTypes implements EventType, ArtifactEventType { WEB_DOWNLOADS(NbBundle.getMessage(WebTypes.class, "WebTypes.webDownloads.name"), "downloads.png", // NON-NLS - TypeUtils.fromEnum(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD), + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED), TopPrivateDomainExtractor.getInstance(), new AttributeExtractor(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH)), @@ -61,7 +61,7 @@ public enum WebTypes implements EventType, ArtifactEventType { //TODO: review description separators WEB_COOKIE(NbBundle.getMessage(WebTypes.class, "WebTypes.webCookies.name"), "cookies.png", // NON-NLS - TypeUtils.fromEnum(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE), + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME), TopPrivateDomainExtractor.getInstance(), new AttributeExtractor(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME)), @@ -69,7 +69,7 @@ public enum WebTypes implements EventType, ArtifactEventType { //TODO: review description separators WEB_BOOKMARK(NbBundle.getMessage(WebTypes.class, "WebTypes.webBookmarks.name"), "bookmarks.png", // NON-NLS - TypeUtils.fromEnum(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK), + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED), TopPrivateDomainExtractor.getInstance(), new AttributeExtractor(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)), @@ -77,7 +77,7 @@ public enum WebTypes implements EventType, ArtifactEventType { //TODO: review description separators WEB_HISTORY(NbBundle.getMessage(WebTypes.class, "WebTypes.webHistory.name"), "history.png", // NON-NLS - TypeUtils.fromEnum(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY), + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED), TopPrivateDomainExtractor.getInstance(), new AttributeExtractor(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)), @@ -85,7 +85,7 @@ public enum WebTypes implements EventType, ArtifactEventType { //TODO: review description separators WEB_SEARCH(NbBundle.getMessage(WebTypes.class, "WebTypes.webSearch.name"), "searchquery.png", // NON-NLS - TypeUtils.fromEnum(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY), + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED), new AttributeExtractor(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT)), TopPrivateDomainExtractor.getInstance(), diff --git a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java index e708fe0b99..ed0357d6fa 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java @@ -84,28 +84,6 @@ import org.sqlite.SQLiteJDBCLoader; */ public class EventDB { - /** - * - * enum to represent keys stored in db_info table - */ - private enum DBInfoKey { - - LAST_ARTIFACT_ID("last_artifact_id"), // NON-NLS - LAST_OBJECT_ID("last_object_id"), // NON-NLS - WAS_INGEST_RUNNING("was_ingest_running"); // NON-NLS - - private final String keyName; - - private DBInfoKey(String keyName) { - this.keyName = keyName; - } - - @Override - public String toString() { - return keyName; - } - } - private static final org.sleuthkit.autopsy.coreutils.Logger LOGGER = Logger.getLogger(EventDB.class.getName()); static { @@ -142,14 +120,12 @@ public class EventDB { private final String dbPath; - private PreparedStatement getDBInfoStmt; private PreparedStatement getEventByIDStmt; private PreparedStatement getMaxTimeStmt; private PreparedStatement getMinTimeStmt; private PreparedStatement getDataSourceIDsStmt; private PreparedStatement getHashSetNamesStmt; private PreparedStatement insertRowStmt; - private PreparedStatement recordDBInfoStmt; private PreparedStatement insertHashSetStmt; private PreparedStatement insertHashHitStmt; private PreparedStatement insertTagStmt; @@ -394,14 +370,6 @@ public class EventDB { return resultIDs; } - long getLastArtfactID() { - return getDBInfo(DBInfoKey.LAST_ARTIFACT_ID, -1); - } - - long getLastObjID() { - return getDBInfo(DBInfoKey.LAST_OBJECT_ID, -1); - } - /** * this relies on the fact that no tskObj has ID 0 but 0 is the default * value for the datasource_id column in the events table. @@ -489,10 +457,6 @@ public class EventDB { return -1l; } - boolean getWasIngestRunning() { - return getDBInfo(DBInfoKey.WAS_INGEST_RUNNING, 0) != 0; - } - /** * create the table and indices if they don't already exist * @@ -614,8 +578,6 @@ public class EventDB { getMaxTimeStmt = prepareStatement("SELECT Max(time) AS max FROM events"); // NON-NLS getMinTimeStmt = prepareStatement("SELECT Min(time) AS min FROM events"); // NON-NLS getEventByIDStmt = prepareStatement("SELECT * FROM events WHERE event_id = ?"); // NON-NLS - recordDBInfoStmt = prepareStatement("INSERT OR REPLACE INTO db_info (key, value) values (?, ?)"); // NON-NLS - getDBInfoStmt = prepareStatement("SELECT value FROM db_info WHERE key = ?"); // NON-NLS insertHashSetStmt = prepareStatement("INSERT OR IGNORE INTO hash_sets (hash_set_name) values (?)"); //NON-NLS selectHashSetStmt = prepareStatement("SELECT hash_set_id FROM hash_sets WHERE hash_set_name = ?"); //NON-NLS insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, event_id) values (?,?)"); //NON-NLS @@ -938,18 +900,6 @@ public class EventDB { return eventIDs; } - void recordLastArtifactID(long lastArtfID) { - recordDBInfo(DBInfoKey.LAST_ARTIFACT_ID, lastArtfID); - } - - void recordLastObjID(Long lastObjID) { - recordDBInfo(DBInfoKey.LAST_OBJECT_ID, lastObjID); - } - - void recordWasIngestRunning(boolean wasIngestRunning) { - recordDBInfo(DBInfoKey.WAS_INGEST_RUNNING, (wasIngestRunning ? 1 : 0)); - } - void rollBackTransaction(EventTransaction trans) { trans.rollback(); } @@ -983,8 +933,7 @@ public class EventDB { try { LOGGER.log(Level.INFO, String.format("sqlite-jdbc version %s loaded in %s mode", // NON-NLS - SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode() - ? "native" : "pure-java")); // NON-NLS + SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode() ? "native" : "pure-java")); // NON-NLS } catch (Exception exception) { LOGGER.log(Level.SEVERE, "Failed to determine if sqlite-jdbc is loaded in native or pure-java mode.", exception); //NON-NLS } @@ -1220,28 +1169,6 @@ public class EventDB { return useSubTypes ? "sub_type" : "base_type"; //NON-NLS } - private long getDBInfo(DBInfoKey key, long defaultValue) { - DBLock.lock(); - try { - getDBInfoStmt.setString(1, key.toString()); - - try (ResultSet rs = getDBInfoStmt.executeQuery()) { - long result = defaultValue; - while (rs.next()) { - result = rs.getLong("value"); // NON-NLS - } - return result; - } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "failed to read key: " + key + " from db_info", ex); // NON-NLS - } finally { - DBLock.unlock(); - } - } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "failed to set key: " + key + " on getDBInfoStmt ", ex); // NON-NLS - } - - return defaultValue; - } private PreparedStatement prepareStatement(String queryString) throws SQLException { PreparedStatement prepareStatement = con.prepareStatement(queryString); @@ -1249,20 +1176,6 @@ public class EventDB { return prepareStatement; } - private void recordDBInfo(DBInfoKey key, long value) { - DBLock.lock(); - try { - recordDBInfoStmt.setString(1, key.toString()); - recordDBInfoStmt.setLong(2, value); - recordDBInfoStmt.executeUpdate(); - } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "failed to set dbinfo key: " + key + " value: " + value, ex); // NON-NLS - } finally { - DBLock.unlock(); - - } - } - /** * inner class that can reference access database connection */ diff --git a/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java b/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java index 6946ded64d..0583b0c175 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java @@ -35,6 +35,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; @@ -44,6 +45,7 @@ import javafx.beans.property.ReadOnlyObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; +import javafx.concurrent.Worker; import javax.swing.JOptionPane; import org.apache.commons.lang3.StringUtils; import org.joda.time.Interval; @@ -54,9 +56,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.timeline.CancellationProgressTask; -import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.EventStripe; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent; @@ -168,7 +168,7 @@ public class EventsRepository { */ public Long getMaxTime() { return maxCache.getUnchecked("max"); // NON-NLS -// return eventDB.getMaxTime(); + } /** @@ -176,31 +176,7 @@ public class EventsRepository { */ public Long getMinTime() { return minCache.getUnchecked("min"); // NON-NLS -// return eventDB.getMinTime(); - } - private void recordLastArtifactID(long lastArtfID) { - eventDB.recordLastArtifactID(lastArtfID); - } - - private void recordWasIngestRunning(Boolean wasIngestRunning) { - eventDB.recordWasIngestRunning(wasIngestRunning); - } - - private void recordLastObjID(Long lastObjID) { - eventDB.recordLastObjID(lastObjID); - } - - public boolean getWasIngestRunning() { - return eventDB.getWasIngestRunning(); - } - - public Long getLastObjID() { - return eventDB.getLastObjID(); - } - - public long getLastArtfactID() { - return eventDB.getLastArtfactID(); } public TimeLineEvent getEventById(Long eventID) { @@ -227,6 +203,10 @@ public class EventsRepository { return eventCountsCache.getUnchecked(params); } + synchronized public int countAllEvents() { + return eventDB.countAllEvents(); + } + private void invalidateCaches() { minCache.invalidateAll(); maxCache.invalidateAll(); @@ -331,18 +311,6 @@ public class EventsRepository { } } - /** - * - * @param lastObjId the value of lastObjId - * @param lastArtfID the value of lastArtfID - * @param injestRunning the value of injestRunning - */ - public void recordDBPopulationState(final long lastObjId, final long lastArtfID, final Boolean injestRunning) { - recordLastObjID(lastObjId); - recordLastArtifactID(lastArtfID); - recordWasIngestRunning(injestRunning); - } - public boolean areFiltersEquivalent(RootFilter f1, RootFilter f2) { return SQLHelper.getSQLWhere(f1).equals(SQLHelper.getSQLWhere(f2)); } @@ -352,27 +320,56 @@ public class EventsRepository { return dbWorker.isRunning(); } + /** + * + * rebuild the entire repo. + * + * @param onStateChange called when he background task changes state. + * Clients can use this to handle failure, or cleanup + * operations for example. + * + * @return the task that will rebuild the repo in a background thread. The + * task has already been started. + */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - public CancellationProgressTask rebuildRepository() { - return rebuildRepository(DBPopulationMode.FULL); - } - - @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - public CancellationProgressTask rebuildTags() { - return rebuildRepository(DBPopulationMode.TAGS_ONLY); + public CancellationProgressTask rebuildRepository(Consumer onStateChange) { + return rebuildRepository(DBPopulationMode.FULL, onStateChange); } /** * - * @param mode the value of mode + * drop and rebuild the tags in the repo. + * + * @param onStateChange called when he background task changes state. + * Clients can use this to handle failure, or cleanup + * operations for example. + * + * @return the task that will rebuild the repo in a background thread. The + * task has already been started. */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - private CancellationProgressTask rebuildRepository(final DBPopulationMode mode) { + public CancellationProgressTask rebuildTags(Consumer onStateChange) { + return rebuildRepository(DBPopulationMode.TAGS_ONLY, onStateChange); + } + + /** + * rebuild the repo. + * + * @param mode the rebuild mode to use. + * @param onStateChange called when he background task changes state. + * Clients can use this to handle failure, or cleanup + * operations for example. + * + * @return the task that will rebuild the repo in a background thread. The + * task has already been started. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) + private CancellationProgressTask rebuildRepository(final DBPopulationMode mode, Consumer onStateChange) { LOGGER.log(Level.INFO, "(re)starting {0} db population task", mode); //NON-NLS if (dbWorker != null) { dbWorker.cancel(); } - dbWorker = new DBPopulationWorker(mode); + dbWorker = new DBPopulationWorker(mode, onStateChange); workerExecutor.execute(dbWorker); return dbWorker; } @@ -437,10 +434,11 @@ public class EventsRepository { } } - DBPopulationWorker(DBPopulationMode mode) { + DBPopulationWorker(DBPopulationMode mode, Consumer onStateChange) { skCase = autoCase.getSleuthkitCase(); tagsManager = autoCase.getServices().getTagsManager(); this.dbPopulationMode = mode; + this.stateProperty().addListener(stateObservable -> onStateChange.accept(getState())); } void restartProgressHandle(String title, String message, Double workDone, double total, Boolean cancellable) { @@ -470,11 +468,6 @@ public class EventsRepository { protected Void call() throws Exception { EventDB.EventTransaction trans = null; - //save paramaters for recording later - long lastObjId = skCase.getLastObjectId(); - long lastArtfID = TimeLineController.getCaseLastArtifactID(skCase); - boolean injestRunning = IngestManager.getInstance().isIngestRunning(); - if (dbPopulationMode == DBPopulationMode.FULL) { //drop old db, and add back MAC and artifact events LOGGER.log(Level.INFO, "Beginning population of timeline db."); // NON-NLS @@ -513,9 +506,6 @@ public class EventsRepository { Platform.runLater(() -> cancellable.set(false)); restartProgressHandle(Bundle.progressWindow_msg_commitingDb(), "", -1D, 1, false); eventDB.commitTransaction(trans); - if (isCancelRequested() == false) { - recordDBPopulationState(lastObjId, lastArtfID, injestRunning); - } eventDB.analyze(); populateFilterData(skCase); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/AbstractFilter.java index c5871454d8..c51b3a82ed 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/AbstractFilter.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.timeline.filters; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.value.ObservableBooleanValue; /** * Base implementation of a {@link Filter}. Implements active property. @@ -38,7 +39,7 @@ public abstract class AbstractFilter implements Filter { } @Override - public SimpleBooleanProperty getDisabledProperty() { + public ObservableBooleanValue disabledProperty() { return disabled; } @@ -67,11 +68,11 @@ public abstract class AbstractFilter implements Filter { return "[" + (isSelected() ? "x" : " ") + "]"; // NON-NLS } - public final boolean isActive() { + public boolean isActive() { return activeProperty.get(); } - public final BooleanBinding activeProperty() { + public BooleanBinding activeProperty() { return activeProperty; } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java index bf4c6a1b07..dff26b1e61 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java @@ -67,6 +67,13 @@ public abstract class CompoundFilter extends Abstr } }); this.subFilters.setAll(subFilters); + + this.selectedProperty().addListener(activeProperty -> { + getSubFilters().forEach(subFilter -> subFilter.setDisabled(isActive() == false)); + }); + this.disabledProperty().addListener(activeProperty -> { + getSubFilters().forEach(subFilter -> subFilter.setDisabled(isActive() == false)); + }); } private void addSubFilterListeners(List newSubfilters) { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java index 06198052af..02318310f1 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.timeline.filters; import java.util.Comparator; import java.util.stream.Collectors; import javafx.beans.binding.Bindings; +import javafx.beans.value.ObservableBooleanValue; import org.openide.util.NbBundle; /** @@ -29,7 +30,6 @@ import org.openide.util.NbBundle; public class DataSourcesFilter extends UnionFilter { public DataSourcesFilter() { - getDisabledProperty().bind(Bindings.size(getSubFilters()).lessThanOrEqualTo(1)); setSelected(false); } @@ -69,7 +69,6 @@ public class DataSourcesFilter extends UnionFilter { .map(DataSourceFilter::getDataSourceID) .filter(t -> t == dataSourceFilter.getDataSourceID()) .findAny().isPresent() == false) { - dataSourceFilter.getDisabledProperty().bind(getDisabledProperty()); getSubFilters().add(dataSourceFilter); getSubFilters().sort(Comparator.comparing(DataSourceFilter::getDisplayName)); } @@ -100,4 +99,10 @@ public class DataSourcesFilter extends UnionFilter { public int hashCode() { return 9; } + + @Override + public ObservableBooleanValue disabledProperty() { + return Bindings.or(super.disabledProperty(), Bindings.size(getSubFilters()).lessThanOrEqualTo(1)); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/Filter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/Filter.java index dc44c8912b..435998a183 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/Filter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/Filter.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.timeline.filters; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.value.ObservableBooleanValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -77,7 +78,7 @@ public interface Filter { */ void setDisabled(Boolean act); - SimpleBooleanProperty getDisabledProperty(); + ObservableBooleanValue disabledProperty(); boolean isDisabled(); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java index 79f705bab0..b7a13184f7 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java @@ -8,6 +8,7 @@ package org.sleuthkit.autopsy.timeline.filters; import java.util.Comparator; import java.util.stream.Collectors; import javafx.beans.binding.Bindings; +import javafx.beans.value.ObservableBooleanValue; import org.openide.util.NbBundle; /** @@ -16,13 +17,12 @@ import org.openide.util.NbBundle; public class HashHitsFilter extends UnionFilter { @Override - @NbBundle.Messages("hashHitsFilter.displayName.text=Only Hash Set Hits") + @NbBundle.Messages("hashHitsFilter.displayName.text=Hash Sets") public String getDisplayName() { return Bundle.hashHitsFilter_displayName_text(); } public HashHitsFilter() { - getDisabledProperty().bind(Bindings.size(getSubFilters()).lessThan(1)); setSelected(false); } @@ -81,4 +81,9 @@ public class HashHitsFilter extends UnionFilter { getSubFilters().sort(Comparator.comparing(HashSetFilter::getDisplayName)); } } + + @Override + public ObservableBooleanValue disabledProperty() { + return Bindings.or(super.disabledProperty(), Bindings.isEmpty(getSubFilters())); + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/RootFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/RootFilter.java index 9034810ed7..2b31978d7b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/RootFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/RootFilter.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.timeline.filters; import java.util.Set; import java.util.stream.Collectors; +import javafx.beans.binding.BooleanBinding; import javafx.collections.FXCollections; /** @@ -70,7 +71,7 @@ public class RootFilter extends IntersectionFilter { public RootFilter copyOf() { Set annonymousSubFilters = getSubFilters().stream() .filter(subFilter -> - !(subFilter.equals(knownFilter) + !(subFilter.equals(knownFilter) || subFilter.equals(tagsFilter) || subFilter.equals(hashFilter) || subFilter.equals(typeFilter) @@ -108,4 +109,17 @@ public class RootFilter extends IntersectionFilter { } return areSubFiltersEqual(this, (CompoundFilter) obj); } + + public boolean isActive() { + return true; + } + + public BooleanBinding activeProperty() { + return new BooleanBinding() { + @Override + protected boolean computeValue() { + return true; + } + }; + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java index 44d71793fe..1ab69a3909 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java @@ -8,6 +8,7 @@ package org.sleuthkit.autopsy.timeline.filters; import java.util.Comparator; import java.util.stream.Collectors; import javafx.beans.binding.Bindings; +import javafx.beans.value.ObservableBooleanValue; import org.openide.util.NbBundle; import org.sleuthkit.datamodel.TagName; @@ -17,13 +18,12 @@ import org.sleuthkit.datamodel.TagName; public class TagsFilter extends UnionFilter { @Override - @NbBundle.Messages("tagsFilter.displayName.text=Only Events Tagged") + @NbBundle.Messages("tagsFilter.displayName.text=Tags") public String getDisplayName() { return Bundle.tagsFilter_displayName_text(); } public TagsFilter() { - getDisabledProperty().bind(Bindings.size(getSubFilters()).lessThan(1)); setSelected(false); } @@ -89,5 +89,8 @@ public class TagsFilter extends UnionFilter { getSubFilters().sort(Comparator.comparing(TagNameFilter::getDisplayName)); } - + @Override + public ObservableBooleanValue disabledProperty() { + return Bindings.or(super.disabledProperty(), Bindings.isEmpty(getSubFilters())); + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java index 362580094c..85a299e5fc 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java @@ -72,7 +72,7 @@ public class TypeFilter extends UnionFilter { } @Override - @NbBundle.Messages("TypeFilter.displayName.text=Event Type Filter") + @NbBundle.Messages("TypeFilter.displayName.text=Event Type") public String getDisplayName() { return (eventType == RootEventType.getInstance()) ? Bundle.TypeFilter_displayName_text() diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/StatusBar.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/StatusBar.java index 3ff0222beb..eb1ba3091a 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/StatusBar.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/StatusBar.java @@ -74,8 +74,8 @@ public class StatusBar extends ToolBar { taskLabel.setVisible(false); HBox.setHgrow(spacer, Priority.ALWAYS); - refreshLabel.visibleProperty().bind(this.controller.getNewEventsFlag()); - refreshLabel.managedProperty().bind(this.controller.getNewEventsFlag()); + refreshLabel.visibleProperty().bind(this.controller.eventsDBStaleProperty()); + refreshLabel.managedProperty().bind(this.controller.eventsDBStaleProperty()); taskLabel.textProperty().bind(this.controller.taskTitleProperty()); messageLabel.textProperty().bind(this.controller.taskMessageProperty()); progressBar.progressProperty().bind(this.controller.taskProgressProperty()); @@ -83,6 +83,5 @@ public class StatusBar extends ToolBar { statusLabel.textProperty().bind(this.controller.getStatusProperty()); statusLabel.visibleProperty().bind(statusLabel.textProperty().isNotEmpty()); - } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java index eb3cf09768..2f56b78f79 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java @@ -347,9 +347,9 @@ final public class VisualizationPanel extends BorderPane { refreshTimeUI(); //populate the viz //this should use an event(EventBus) , not this weird observable pattern - controller.getNeedsHistogramRebuild().addListener((observable, oldValue, newValue) -> { - if (newValue) { - refreshHistorgram(); + controller.eventsDBStaleProperty().addListener(staleProperty -> { + if (controller.isEventsDBStale()) { + Platform.runLater(VisualizationPanel.this::refreshHistorgram); } }); refreshHistorgram(); @@ -569,7 +569,7 @@ final public class VisualizationPanel extends BorderPane { titledPane.setText(Bundle.NoEventsDialog_titledPane_text()); noEventsDialogLabel.setText(NbBundle.getMessage(NoEventsDialog.class, "VisualizationPanel.noEventsDialogLabel.text")); // NON-NLS - + dismissButton.setOnAction(actionEvent -> closeCallback.run()); ActionUtils.configureButton(new ZoomToEvents(controller), zoomButton); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterCheckBoxCellFactory.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterCheckBoxCellFactory.java index 535289c6aa..689bb47702 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterCheckBoxCellFactory.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterCheckBoxCellFactory.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.timeline.ui.filtering; import java.util.function.Supplier; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.value.ObservableBooleanValue; import javafx.scene.control.CheckBox; import javafx.scene.control.IndexedCell; import org.sleuthkit.autopsy.timeline.filters.AbstractFilter; @@ -29,7 +30,7 @@ class FilterCheckBoxCellFactory extends AbstractFXCell private final CheckBox checkBox = new CheckBox(); private SimpleBooleanProperty selectedProperty; - private SimpleBooleanProperty disabledProperty; + private ObservableBooleanValue disabledProperty; @Override protected void configureCell(IndexedCell cell, X item, boolean empty, Supplier supplier) { @@ -37,18 +38,17 @@ class FilterCheckBoxCellFactory extends AbstractFXCell checkBox.selectedProperty().unbindBidirectional(selectedProperty); } if (disabledProperty != null) { - checkBox.disableProperty().unbindBidirectional(disabledProperty); + checkBox.disableProperty().unbind();//disabledProperty); } if (item == null) { - cell.setText(null); cell.setGraphic(null); } else { - cell.setText(item.getDisplayName()); + checkBox.setText(item.getDisplayName()); selectedProperty = item.selectedProperty(); checkBox.selectedProperty().bindBidirectional(selectedProperty); - disabledProperty = item.getDisabledProperty(); - checkBox.disableProperty().bindBidirectional(disabledProperty); + disabledProperty = item.disabledProperty(); + checkBox.disableProperty().bind(disabledProperty); cell.setGraphic(checkBox); } } diff --git a/CoreLibs/manifest.mf b/CoreLibs/manifest.mf index bba0e51547..e2386f67ce 100644 --- a/CoreLibs/manifest.mf +++ b/CoreLibs/manifest.mf @@ -1,5 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.corelibs/3 +OpenIDE-Module-Implementation-Version: 4 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/corelibs/Bundle.properties OpenIDE-Module-Specification-Version: 1.1 AutoUpdate-Show-In-Client: true diff --git a/ImageGallery/manifest.mf b/ImageGallery/manifest.mf index 25b0a0656d..79c24ee687 100644 --- a/ImageGallery/manifest.mf +++ b/ImageGallery/manifest.mf @@ -1,5 +1,5 @@ Manifest-Version: 1.0 -OpenIDE-Module: org.sleuthkit.autopsy.imagegallery/1 -OpenIDE-Module-Implementation-Version: 1 +OpenIDE-Module: org.sleuthkit.autopsy.imagegallery/2 +OpenIDE-Module-Implementation-Version: 2 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/imagegallery/Bundle.properties diff --git a/ImageGallery/nbproject/project.properties b/ImageGallery/nbproject/project.properties index f61ae8d42a..e400c96aab 100644 --- a/ImageGallery/nbproject/project.properties +++ b/ImageGallery/nbproject/project.properties @@ -5,4 +5,4 @@ license.file=LICENSE-2.0.txt nbm.homepage=http://www.sleuthkit.org/ nbm.needs.restart=true project.license=imagegallery -spec.version.base=1.0 +spec.version.base=2.0 diff --git a/ImageGallery/nbproject/project.xml b/ImageGallery/nbproject/project.xml index 2a28ce3deb..bff28c8d43 100644 --- a/ImageGallery/nbproject/project.xml +++ b/ImageGallery/nbproject/project.xml @@ -103,7 +103,7 @@ 10 - 10.0.11 + 10.5 diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java index 764a4fa4d1..e5822569c8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java @@ -23,16 +23,16 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import static java.util.Objects.isNull; -import java.util.Optional; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.imageio.ImageIO; -import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; /** @@ -149,13 +149,13 @@ public enum FileTypeUtils { return Collections.unmodifiableSet(supportedExtensions); } - static synchronized FileTypeDetector getFileTypeDetector() { + static synchronized FileTypeDetector getFileTypeDetector() throws FileTypeDetector.FileTypeDetectorInitException { + /* + * TODO: EUR-740 recreate FileTypeDetector when the user creates new + * user defined file types + */ if (isNull(FILE_TYPE_DETECTOR)) { - try { - FILE_TYPE_DETECTOR = new FileTypeDetector(); - } catch (FileTypeDetector.FileTypeDetectorInitException ex) { - LOGGER.log(Level.SEVERE, "Failed to initialize File Type Detector, will fall back on extensions in some situations.", ex); //NON-NLS - } + FILE_TYPE_DETECTOR = new FileTypeDetector(); } return FILE_TYPE_DETECTOR; } @@ -169,24 +169,12 @@ public enum FileTypeUtils { * * @return true if this file is supported or false if not */ - public static boolean isDrawable(AbstractFile file) throws TskCoreException { - return hasDrawableMimeType(file).orElseGet(() -> { - return FileTypeUtils.supportedExtensions.contains(file.getNameExtension().toLowerCase()) - || ImageUtils.isJpegFileHeader(file) - || ImageUtils.isPngFileHeader(file); - }); - } - - public static boolean isGIF(AbstractFile file) { - return ImageUtils.isGIF(file); - } - - public static Optional getMimeType(AbstractFile file) throws TskCoreException { - return Optional.ofNullable(file.getMIMEType()); + public static boolean isDrawable(AbstractFile file) throws TskCoreException, FileTypeDetector.FileTypeDetectorInitException { + return hasDrawableMIMEType(file); } static boolean isDrawableMimeType(String mimeType) { - if (isNull(mimeType)) { + if (StringUtils.isBlank(mimeType)) { return false; } else { String mimeTypeLower = mimeType.toLowerCase(); @@ -197,6 +185,10 @@ public enum FileTypeUtils { } /** + * + * TODO: EUR-740 recreate FileTypeDetector when the user creates new user + * defined file types + * * does the given file have drawable/supported mime type * * @param file @@ -205,8 +197,9 @@ public enum FileTypeUtils { * type. False if a non image/video mimetype. empty Optional if a * mimetype could not be detected. */ - static Optional hasDrawableMimeType(AbstractFile file) throws TskCoreException { - return getMimeType(file).map(FileTypeUtils::isDrawableMimeType); + static boolean hasDrawableMIMEType(AbstractFile file) throws TskCoreException, FileTypeDetector.FileTypeDetectorInitException { + String mimeType = getFileTypeDetector().detect(file).toLowerCase(); + return isDrawableMimeType(mimeType) || (mimeType.equals("audio/x-aiff") && "tiff".equalsIgnoreCase(file.getNameExtension())); } /** @@ -218,16 +211,31 @@ public enum FileTypeUtils { * application/x-shockwave-flash, etc) or, if no mimetype is * available, a video extension. */ - public static boolean isVideoFile(AbstractFile file) { + public static boolean hasVideoMIMEType(AbstractFile file) { try { - return getMimeType(file) - .map(String::toLowerCase) - .map(mimeType - -> mimeType.startsWith("video/") - || videoMimeTypes.contains(mimeType)) - .orElseGet(() -> FileTypeUtils.videoExtensions.contains(file.getNameExtension())); - } catch (TskCoreException ex) { - return FileTypeUtils.videoExtensions.contains(file.getNameExtension()); + String mimeType = getFileTypeDetector().detect(file).toLowerCase(); + return mimeType.startsWith("video/") || videoMimeTypes.contains(mimeType); + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error determining MIME type of " + getContentPathSafe(file), ex); + return false; + } + } + + /** + * Get the unique path for the content, or if that fails, just return the + * name. + * + * @param content + * + * @return + */ + static String getContentPathSafe(Content content) { + try { + return content.getUniquePath(); + } catch (TskCoreException tskCoreException) { + String contentName = content.getName(); + LOGGER.log(Level.SEVERE, "Failed to get unique path for " + contentName, tskCoreException); //NOI18N NON-NLS + return contentName; } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 246fb00154..9794232b57 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,16 +20,13 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; -import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.property.ReadOnlyBooleanProperty; @@ -79,14 +76,12 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.FileSystem; -import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.VirtualDirectory; /** * Connects different parts of ImageGallery together and is hub for flow of @@ -853,23 +848,15 @@ public final class ImageGalleryController implements Executor { if (known) { taskDB.removeFile(f.getId(), tr); //remove known files } else { - Optional mimeType = FileTypeUtils.getMimeType(f); - if (mimeType.isPresent()) { - //mime type - if (FileTypeUtils.isDrawableMimeType(mimeType.get())) { //supported mimetype => analyzed + + try { + if (FileTypeUtils.hasDrawableMIMEType(f)) { //supported mimetype => analyzed taskDB.updateFile(DrawableFile.create(f, true, false), tr); } else { //unsupported mimtype => analyzed but shouldn't include taskDB.removeFile(f.getId(), tr); } - } else { - //no mime tyoe - if (FileTypeUtils.isDrawable(f)) { - //no mime type but supported => add as not analyzed - taskDB.insertFile(DrawableFile.create(f, false, false), tr); - } else { - //no mime type, not supported => remove ( should never get here) - taskDB.removeFile(f.getId(), tr); - } + } catch (FileTypeDetector.FileTypeDetectorInitException ex) { + throw new RuntimeException(ex); } } } @@ -916,37 +903,8 @@ public final class ImageGalleryController implements Executor { @Override List getFiles() throws TskCoreException { - if (dataSource instanceof Image) { - List fileSystems = ((Image) dataSource).getFileSystems(); - if (fileSystems.isEmpty()) { - /* - * no filesystems, don't bother with the initial population, - * just sort things out on file_done events - */ - progressHandle.finish(); - return Collections.emptyList(); - } - //use this clause to only grab files from the newly added filesystems. - String fsQuery = fileSystems.stream() - .map(fileSystem -> String.valueOf(fileSystem.getId())) - .collect(Collectors.joining(" OR fs_obj_id = ", "(fs_obj_id = ", ") ")); //NON-NLS - - return tskCase.findAllFilesWhere(fsQuery + " AND " + DRAWABLE_QUERY); //NON-NLS - } else if (dataSource instanceof VirtualDirectory) { - /* - * fs_obj_id is set only for file system files, so we will match - * the VirtualDirectory's name in the parent path. - * - * TODO: A future database schema could probably make this - * cleaner. If we had a datasource_id column in the files table - * we could just match agains that. - */ - return tskCase.findAllFilesWhere(" parent_path LIKE '/" + dataSource.getName() + "/%' AND " + DRAWABLE_QUERY); //NON-NLS - } else { - String msg = "Uknown datasource type: " + dataSource.getClass().getName(); - LOGGER.log(Level.SEVERE, msg); - throw new IllegalArgumentException(msg); - } + long datasourceID = dataSource.getDataSource().getId(); + return tskCase.findAllFilesWhere("data_source_obj_id = " + datasourceID + " AND " + DRAWABLE_QUERY); } @Override @@ -1002,10 +960,11 @@ public final class ImageGalleryController implements Executor { //this file would have gotten scooped up in initial grab, but actually we don't need it queueDBWorkerTask(new RemoveFileTask(file, db)); } - } catch (TskCoreException ex) { + } catch (TskCoreException | FileTypeDetector.FileTypeDetectorInitException ex) { //TODO: What to do here? - LOGGER.log(Level.WARNING, "Unable to determine if file is drawable and not known. Not making any changes to DB", ex); //NON-NLS - throw new RuntimeException(ex); + LOGGER.log(Level.SEVERE, "Unable to determine if file is drawable and not known. Not making any changes to DB", ex); //NON-NLS + MessageNotifyUtil.Notify.error("Image Gallery Error", + "Unable to determine if file is drawable and not known. Not making any changes to DB. See the logs for details."); } } } else { //TODO: keep track of what we missed for later diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java index 770df56132..a5f13c1d9a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java @@ -22,11 +22,11 @@ import java.nio.file.Path; import java.nio.file.Paths; import org.apache.commons.lang3.StringUtils; import static org.apache.commons.lang3.StringUtils.isNotBlank; - import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -105,7 +105,7 @@ public class ImageGalleryModule { * @return true if the given {@link AbstractFile} is "drawable" and not * 'known', else false */ - public static boolean isDrawableAndNotKnown(AbstractFile abstractFile) throws TskCoreException { + public static boolean isDrawableAndNotKnown(AbstractFile abstractFile) throws TskCoreException, FileTypeDetector.FileTypeDetectorInitException { return (abstractFile.getKnown() != TskData.FileKnown.KNOWN) && FileTypeUtils.isDrawable(abstractFile); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java index dfd60e5d13..78b260e731 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java @@ -126,7 +126,7 @@ public enum ThumbnailCache { */ private Image load(DrawableFile file) { - if (FileTypeUtils.isGIF(file.getAbstractFile())) { + if (ImageUtils.isGIF(file.getAbstractFile())) { //directly read gif to preserve potential animation, //NOTE: not saved to disk! return new Image(new BufferedInputStream(new ReadContentInputStream(file.getAbstractFile())), MAX_THUMBNAIL_SIZE, MAX_THUMBNAIL_SIZE, true, true); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index bf46596ed5..e7d9dc0a8d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -1176,8 +1176,7 @@ public final class DrawableDB { */ public boolean isVideoFile(AbstractFile f) { return isNull(f) ? false - : videoFileMap.computeIfAbsent(f.getId(), id -> FileTypeUtils.isVideoFile(f)); - + : videoFileMap.computeIfAbsent(f.getId(), id -> FileTypeUtils.hasVideoMIMEType(f)); } /** @@ -1242,8 +1241,8 @@ public final class DrawableDB { String fileIdsList = "(" + StringUtils.join(fileIDs, ",") + " )"; //count the fileids that are in the given list and don't have a non-zero category assigned to them. - String name - = "SELECT COUNT(obj_id) FROM tsk_files where obj_id IN " + fileIdsList //NON-NLS + String name = + "SELECT COUNT(obj_id) FROM tsk_files where obj_id IN " + fileIdsList //NON-NLS + " AND obj_id NOT IN (SELECT obj_id FROM content_tags WHERE content_tags.tag_name_id IN " + catTagNameIDs + ")"; //NON-NLS try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery(name); ResultSet resultSet = executeQuery.getResultSet();) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 678069db9d..2f86c47ad6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -60,7 +60,7 @@ public abstract class DrawableFile { private static final Logger LOGGER = Logger.getLogger(DrawableFile.class.getName()); public static DrawableFile create(AbstractFile abstractFileById, boolean analyzed) { - return create(abstractFileById, analyzed, FileTypeUtils.isVideoFile(abstractFileById)); + return create(abstractFileById, analyzed, FileTypeUtils.hasVideoMIMEType(abstractFileById)); } /** diff --git a/KeywordSearch/manifest.mf b/KeywordSearch/manifest.mf index df31f51f32..8d28239264 100644 --- a/KeywordSearch/manifest.mf +++ b/KeywordSearch/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/6 -OpenIDE-Module-Implementation-Version: 15 +OpenIDE-Module-Implementation-Version: 16 OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 43b6b9f390..a0c6d6ff4b 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -95,7 +95,7 @@ 10 - 10.0 + 10.5 diff --git a/NEWS.txt b/NEWS.txt index 53c2d3fb0c..2922552cf5 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,3 +1,14 @@ +---------------- VERSION 4.1.0 -------------- +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. +- 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. +- Local/GMT time preference is used in reports. +- User has option to choose display name for logical/local file set data sources. +- Assorted bug fixes and minor enhancements. + ---------------- VERSION 4.0.0 -------------- Improvements: - Collaboration supported by optional multi-user cases with centralized data and services diff --git a/RecentActivity/manifest.mf b/RecentActivity/manifest.mf index 8b8da4b3b6..3121c6b8ca 100644 --- a/RecentActivity/manifest.mf +++ b/RecentActivity/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.recentactivity/6 -OpenIDE-Module-Implementation-Version: 14 +OpenIDE-Module-Implementation-Version: 15 OpenIDE-Module-Layer: org/sleuthkit/autopsy/recentactivity/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/recentactivity/Bundle.properties OpenIDE-Module-Requires: diff --git a/RecentActivity/nbproject/project.xml b/RecentActivity/nbproject/project.xml index bf7bb93662..28d1cc24f7 100644 --- a/RecentActivity/nbproject/project.xml +++ b/RecentActivity/nbproject/project.xml @@ -52,7 +52,7 @@ 10 - 10.0 + 10.5 diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RecentDocumentsByLnk.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RecentDocumentsByLnk.java index f97603974e..bb200551fb 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RecentDocumentsByLnk.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RecentDocumentsByLnk.java @@ -98,10 +98,7 @@ class RecentDocumentsByLnk extends Extract { boolean unalloc = recentFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC) || recentFile.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC); if (unalloc == false) { - logger.log(Level.SEVERE, "Error lnk parsing the file to get recent files" + recentFile, e); //NON-NLS - this.addErrorMessage( - NbBundle.getMessage(this.getClass(), "RecentDocumentsByLnk.getRecDoc.errParsingFile", - this.getName(), recentFile.getName())); + logger.log(Level.WARNING, "Error lnk parsing the file to get recent files {0}", recentFile); //NON-NLS } continue; } diff --git a/ScalpelCarver/manifest.mf b/ScalpelCarver/manifest.mf index 8fb11a1cc4..97d1291613 100644 --- a/ScalpelCarver/manifest.mf +++ b/ScalpelCarver/manifest.mf @@ -1,4 +1,5 @@ Manifest-Version: 1.0 -OpenIDE-Module: org.sleuthkit.autopsy.scalpel +OpenIDE-Module: org.sleuthkit.autopsy.scalpel/1 +OpenIDE-Module-Implementation-Version: 2 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/scalpel/Bundle.properties OpenIDE-Module-Specification-Version: 1.0 diff --git a/ScalpelCarver/nbproject/project.xml b/ScalpelCarver/nbproject/project.xml index 866c390d45..0affc73b48 100644 --- a/ScalpelCarver/nbproject/project.xml +++ b/ScalpelCarver/nbproject/project.xml @@ -27,8 +27,8 @@ - 10 - 10.0 + 11 + 11.0 diff --git a/Testing/manifest.mf b/Testing/manifest.mf index 7f246db06f..51d75b7ab6 100644 --- a/Testing/manifest.mf +++ b/Testing/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: false OpenIDE-Module: org.sleuthkit.autopsy.testing/3 -OpenIDE-Module-Implementation-Version: 8 +OpenIDE-Module-Implementation-Version: 9 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/testing/Bundle.properties diff --git a/Testing/nbproject/project.xml b/Testing/nbproject/project.xml index eac0450c0a..8d39122411 100644 --- a/Testing/nbproject/project.xml +++ b/Testing/nbproject/project.xml @@ -12,7 +12,7 @@ 10 - 10.0 + 10.5 @@ -21,7 +21,7 @@ 6 - 6.0 + 6.3 diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index bb53ec0974..1f081e06bd 100755 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -234,7 +234,7 @@ public class RegressionTest extends TestCase { for (String database : databases) { JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import"); importButtonOperator.pushNoBlock(); - JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false); + JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Database", false, false); JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog); JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0); browseButtonOperator.pushNoBlock(); diff --git a/thunderbirdparser/manifest.mf b/thunderbirdparser/manifest.mf index 3e793b1cb0..74d710d518 100644 --- a/thunderbirdparser/manifest.mf +++ b/thunderbirdparser/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.sleuthkit.autopsy.thunderbirdparser/4 -OpenIDE-Module-Implementation-Version: 15 +OpenIDE-Module-Implementation-Version: 16 OpenIDE-Module-Layer: org/sleuthkit/autopsy/thunderbirdparser/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/thunderbirdparser/Bundle.properties diff --git a/thunderbirdparser/nbproject/project.xml b/thunderbirdparser/nbproject/project.xml index d28caa4d6f..5d0dc34ef4 100644 --- a/thunderbirdparser/nbproject/project.xml +++ b/thunderbirdparser/nbproject/project.xml @@ -28,7 +28,7 @@ 10 - 10.0 + 10.5 @@ -37,7 +37,7 @@ 6 - 6.0 + 6.3