Merge remote-tracking branch 'upstream/develop' into timeline-event-mgr

# Conflicts:
#	Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java
#	RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chrome.java
#	RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java
#	RecentActivity/src/org/sleuthkit/autopsy/recentactivity/FirefoxExtractor.java
#	RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java
This commit is contained in:
millmanorama 2018-11-08 16:23:54 +01:00
commit 1bbee98a78
72 changed files with 2654 additions and 1107 deletions

View File

@ -23,6 +23,8 @@
<dependency conf="core->default" org="com.adobe.xmp" name="xmpcore" rev="5.1.2"/>
<dependency conf="core->default" org="org.apache.zookeeper" name="zookeeper" rev="3.4.6"/>
<dependency conf="core->default" org="com.healthmarketscience.jackcess" name="jackcess" rev="2.2.0"/>
<dependency conf="core->default" org="com.healthmarketscience.jackcess" name="jackcess-encrypt" rev="2.1.4"/>
<dependency conf="core->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/>
<dependency conf="core->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/>

View File

@ -18,8 +18,8 @@ file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
file.reference.sqlite-jdbc-3.8.11.jar=release\\modules\\ext\\sqlite-jdbc-3.8.11.jar
file.reference.StixLib.jar=release/modules/ext/StixLib.jar
file.reference.bcprov-jdk15on-1.54.jar=release/modules/ext/bcprov-jdk15on-1.54.jar
file.reference.jackcess-2.1.8.jar=release/modules/ext/jackcess-2.1.8.jar
file.reference.jackcess-encrypt-2.1.2.jar=release/modules/ext/jackcess-encrypt-2.1.2.jar
file.reference.jackcess-2.2.0.jar=release/modules/ext/jackcess-2.2.0.jar
file.reference.jackcess-encrypt-2.1.4.jar=release/modules/ext/jackcess-encrypt-2.1.4.jar
file.reference.jempbox-1.8.13.jar=release/modules/ext/jempbox-1.8.13.jar
file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0.1.jar
file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar
@ -29,7 +29,7 @@ file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-tran
file.reference.fontbox-2.0.8.jar=release/modules/ext/fontbox-2.0.8.jar
file.reference.pdfbox-2.0.8.jar=release/modules/ext/pdfbox-2.0.8.jar
file.reference.pdfbox-tools-2.0.8.jar=release/modules/ext/pdfbox-tools-2.0.8.jar
file.reference.sleuthkit-postgresql-4.6.3.jar=release/modules/ext/sleuthkit-postgresql-4.6.3.jar
file.reference.sleuthkit-postgresql-4.6.4.jar=release/modules/ext/sleuthkit-postgresql-4.6.4.jar
file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar
file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar

View File

@ -342,8 +342,8 @@
<package>org.sleuthkit.datamodel</package>
</public-packages>
<class-path-extension>
<runtime-relative-path>ext/jackcess-2.1.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-2.1.8.jar</binary-origin>
<runtime-relative-path>ext/jackcess-2.2.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-2.2.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
@ -394,8 +394,8 @@
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.3.jar</binary-origin>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.4.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.4.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path>
@ -482,8 +482,8 @@
<binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackcess-encrypt-2.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-encrypt-2.1.2.jar</binary-origin>
<runtime-relative-path>ext/jackcess-encrypt-2.1.4.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-encrypt-2.1.4.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path>

View File

@ -122,6 +122,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TimelineManager;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
import org.sleuthkit.autopsy.coreutils.StopWatch;
/**
* An Autopsy case. Currently, only one case at a time may be open.
@ -743,11 +744,15 @@ public class Case {
"Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
})
public static void deleteCase(CaseMetadata metadata) throws CaseActionException {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
synchronized (caseActionSerializationLock) {
if (null != currentCase) {
throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
}
}
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to acquire caseActionSerializationLock (Java monitor in Case class) for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
/*
* Set up either a GUI progress indicator without a cancel button (can't
@ -769,10 +774,19 @@ public class Case {
* cannot be deleted if another node has it open.
*/
progressIndicator.progress(Bundle.Case_progressMessage_checkingForOtherUser());
stopWatch.reset();
stopWatch.start();
try (CoordinationService.Lock dirLock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, metadata.getCaseDirectory())) {
assert (null != dirLock);
deleteCase(metadata, progressIndicator);
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to acquire case directory coordination service lock for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
if (dirLock != null) {
deleteCase(metadata, progressIndicator);
} else {
throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
}
} catch (CoordinationServiceException ex) {
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to fail to acquire case directory coordination service lock for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
}
}
@ -982,11 +996,13 @@ public class Case {
"Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
})
private static void deleteCase(CaseMetadata metadata, ProgressIndicator progressIndicator) throws CaseActionException {
StopWatch stopWatch = new StopWatch();
boolean errorsOccurred = false;
if (CaseType.MULTI_USER_CASE == metadata.getCaseType()) {
/*
* Delete the case database from the database server.
*/
stopWatch.start();
try {
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDatabase());
CaseDbConnectionInfo db;
@ -996,10 +1012,14 @@ public class Case {
Statement statement = connection.createStatement();) {
String deleteCommand = "DROP DATABASE \"" + metadata.getCaseDatabaseName() + "\""; //NON-NLS
statement.execute(deleteCommand);
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to delete case database for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
}
} catch (UserPreferencesException | ClassNotFoundException | SQLException ex) {
logger.log(Level.SEVERE, String.format("Failed to delete case database %s for %s (%s) in %s", metadata.getCaseDatabaseName(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()), ex);
errorsOccurred = true;
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to fail delete case database for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
}
}
@ -1009,10 +1029,16 @@ public class Case {
progressIndicator.progress(Bundle.Case_progressMessage_deletingTextIndex());
for (KeywordSearchService searchService : Lookup.getDefault().lookupAll(KeywordSearchService.class)) {
try {
stopWatch.reset();
stopWatch.start();
searchService.deleteTextIndex(metadata);
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to delete text index for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
} catch (KeywordSearchServiceException ex) {
logger.log(Level.SEVERE, String.format("Failed to delete text index for %s (%s) in %s", metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()), ex);
errorsOccurred = true;
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to fail to delete text index for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
}
}
@ -1020,9 +1046,16 @@ public class Case {
* Delete the case directory.
*/
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDirectory());
stopWatch.reset();
stopWatch.start();
if (!FileUtil.deleteDir(new File(metadata.getCaseDirectory()))) {
logger.log(Level.SEVERE, String.format("Failed to delete case directory for %s (%s) in %s", metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
errorsOccurred = true;
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to fail to delete case directory for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
} else {
stopWatch.stop();
logger.log(Level.INFO, String.format("Used %d s to delete case directory for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
}
/*
@ -1576,11 +1609,13 @@ public class Case {
}
/**
* Notifies case event subscribers that a central repository comment has been changed.
*
* Notifies case event subscribers that a central repository comment has
* been changed.
*
* This should not be called from the event dispatch thread (EDT)
*
* @param contentId the objectId for the Content which has had its central repo comment changed
*
* @param contentId the objectId for the Content which has had its central
* repo comment changed
* @param newComment the new value of the comment
*/
public void notifyCentralRepoCommentChanged(long contentId, String newComment) {
@ -1836,7 +1871,7 @@ public class Case {
progressIndicator.progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
acquireSharedCaseDirLock(metadata.getCaseDirectory());
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(metadata.getCaseDirectory())) {
assert (null != resourcesLock);
assert(resourcesLock != null); // Use reference to avoid compile time warning.
open(isNewCase, progressIndicator);
} catch (CaseActionException ex) {
releaseSharedCaseDirLock(getMetadata().getCaseDirectory());
@ -2414,7 +2449,7 @@ public class Case {
* @throws CaseActionException with a user-friendly message if the lock
* cannot be acquired.
*/
@Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
@Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory"})
private void acquireSharedCaseDirLock(String caseDir) throws CaseActionException {
try {
caseDirLock = CoordinationService.getInstance().tryGetSharedLock(CategoryNode.CASES, caseDir, DIR_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);

View File

@ -21,8 +21,6 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File;
import java.util.Calendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
@ -39,6 +37,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
/**
* Panel for adding an image file such as .img, .E0x, .00x, etc. Allows the user
@ -72,11 +71,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
initComponents();
// Populate the drop down list of time zones
for (String id : SimpleTimeZone.getAvailableIDs()) {
timeZoneComboBox.addItem(timeZoneToString(TimeZone.getTimeZone(id)));
}
// set the selected timezone to the current timezone
timeZoneComboBox.setSelectedItem(timeZoneToString(Calendar.getInstance().getTimeZone()));
createTimeZoneList();
// Populate the drop down list of sector size options
for (String choice : SECTOR_SIZE_CHOICES) {
@ -95,6 +90,20 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
}
}
/**
* Creates the drop down list for the time zones and defaults the selection
* to the local machine time zone.
*/
private void createTimeZoneList() {
List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
for (String timeZone : timeZoneList) {
timeZoneComboBox.addItem(timeZone);
}
// set the selected timezone
timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}
/**
* Creates and returns an instance of a ImageFilePanel.
*
@ -348,21 +357,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
}
}
/**
* Get a string representation of a TimeZone for use in the drop down list.
*
* @param zone The TimeZone to make a string for
*
* @return A string representation of a TimeZone for use in the drop down
* list.
*/
static private String timeZoneToString(TimeZone zone) {
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
return String.format("(GMT%+d:%02d) %s", hour, minutes, zone.getID()); //NON-NLS
}
@Override
public void insertUpdate(DocumentEvent e) {
updateHelper();

View File

@ -21,8 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File;
import java.nio.file.Paths;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
@ -32,6 +31,7 @@ import org.sleuthkit.autopsy.coreutils.LocalDisk;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
/**
@ -469,36 +469,13 @@ final class LocalDiskPanel extends JPanel {
* to the local machine time zone.
*/
public void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); //NON-NLS
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneComboBox.addItem(item);
List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
for (String timeZone : timeZoneList) {
timeZoneComboBox.addItem(timeZone);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID()); //NON-NLS
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}
/**

View File

@ -369,7 +369,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor, AutoIngestDat
@Override
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
List<String> filePaths = Arrays.asList(new String[]{dataSourcePath.toString()});
run(deviceId, deviceId, filePaths, progressMonitor, callBack);
run(deviceId, "", filePaths, progressMonitor, callBack);
}
/**

View File

@ -492,6 +492,7 @@ public class FileManager implements Closeable {
}
}
trans.commit();
trans = null;
/*
* Publish content added events for the added files and directories.
@ -502,15 +503,14 @@ public class FileManager implements Closeable {
return dataSource;
} catch (TskCoreException ex) {
} finally {
if (null != trans) {
try {
trans.rollback();
} catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception", ex);
}
}
throw ex;
}
}

View File

@ -2960,14 +2960,10 @@ abstract class AbstractSqlEamDb implements EamDb {
resultSet.getString("poc_phone"));
}
CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name"));
eamCase.setOrg(eamOrg);
eamCase.setCreationDate(resultSet.getString("creation_date"));
eamCase.setCaseNumber(resultSet.getString("case_number"));
eamCase.setExaminerName(resultSet.getString("examiner_name"));
eamCase.setExaminerEmail(resultSet.getString("examiner_email"));
eamCase.setExaminerPhone(resultSet.getString("examiner_phone"));
eamCase.setNotes(resultSet.getString("notes"));
CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
return eamCase;
}
@ -3017,7 +3013,6 @@ abstract class AbstractSqlEamDb implements EamDb {
if (null == resultSet) {
return null;
}
// @@@ We should have data source ID in the previous query instead of passing -1 into the below constructor
return new CorrelationAttributeInstance(
aType,
resultSet.getString("value"),

View File

@ -66,7 +66,7 @@ GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to
GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties
GlobalSettingsPanel.organizationPanel.border.title=Organizations
GlobalSettingsPanel.casesPanel.border.title=Case Details
GlobalSettingsPanel.showCasesButton.text=Show Cases
GlobalSettingsPanel.showCasesButton.text=Manage Cases
ShowCasesDialog.closeButton.AccessibleContext.accessibleName=Close
ShowCasesDialog.closeButton.actionCommand=Close
ShowCasesDialog.closeButton.text=Close
@ -76,3 +76,12 @@ GlobalSettingsPanel.Case\ Details.AccessibleContext.accessibleName=Cases Details
ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription=Click column name to sort.
GlobalSettingsPanel.casesTextArea.text=Display table that lists central repository case details.
GlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to central repository settings when ingest is running!
ManageCasesDialog.examinerPhoneLabel.text=Examiner Phone:
ManageCasesDialog.examinerNameLabel.text=Examiner Name:
ManageCasesDialog.examinerEmailLabel.text=Examiner Email:
ManageCasesDialog.caseNumberLabel.text=Case Number:
ManageCasesDialog.orgLabel.text=Organization:
ManageCasesDialog.closeButton.text=Close
ManageCasesDialog.notesLabel.text=Notes:
ManageCasesDialog.dataSourcesLabel.text=Data Sources:
ManageCasesDialog.caseInfoLabel.text=Case Info:

View File

@ -0,0 +1,131 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.Collections;
import java.util.List;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
/**
* An object to contain both a CorrelationCase and the list of
* CorrelationDataSources which are associated with that case.
*/
class CaseDataSourcesWrapper {
private final CorrelationCase eamCase;
private final List<CorrelationDataSource> dataSources;
/**
* Create a new CaseDataSourcesWrapper object.
*
* @param correlationCase - the CorrelationCase which is being represented
* @param dataSourceList - the list of CorrelationDataSource objects which
* are associated with the CorrelationCase
*/
CaseDataSourcesWrapper(CorrelationCase correlationCase, List<CorrelationDataSource> dataSourceList) {
eamCase = correlationCase;
dataSources = dataSourceList;
}
/**
* Get the display name of the CorrelationCase.
*
* @return the display name of the CorrelationCase.
*/
String getDisplayName() {
return eamCase.getDisplayName();
}
/**
* Get the list of CorrelationDataSources associated with the
* CorrelationCase.
*
* @return the list of CorrelationDataSources associated with the
* CorrelationCase.
*/
List<CorrelationDataSource> getDataSources() {
return Collections.unmodifiableList(dataSources);
}
/**
* Get the creation date of the CorrelationCase.
*
* @return the creation date of the CorrelationCase.
*/
String getCreationDate() {
return eamCase.getCreationDate();
}
/**
* Get the organization name of the CorrelationCase.
*
* @return the organization name of the CorrelationCase.
*/
String getOrganizationName() {
EamOrganization org = eamCase.getOrg();
return org == null ? "" : org.getName();
}
/**
* Get the case number of the CorrelationCase.
*
* @return the case number of the CorrelationCase.
*/
String getCaseNumber() {
return eamCase.getCaseNumber();
}
/**
* Get the examiner name of the CorrelationCase.
*
* @return the examiner name of the CorrelationCase.
*/
String getExaminerName() {
return eamCase.getExaminerName();
}
/**
* Get the examiner email of the CorrelationCase.
*
* @return the examiner email of the CorrelationCase.
*/
String getExaminerEmail() {
return eamCase.getExaminerEmail();
}
/**
* Get the notes of the CorrelationCase.
*
* @return the notes of the CorrelationCase.
*/
String getNotes() {
return eamCase.getNotes();
}
/**
* Get the examiner phone number of the CorrelationCase.
*
* @return the examiner phone number of the CorrelationCase.
*/
String getExaminerPhone() {
return eamCase.getExaminerPhone();
}
}

View File

@ -0,0 +1,156 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
/**
* Model for cells to display correlation case information
*/
class CasesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
/**
* list of Eam Cases from central repository.
*/
private final List<CaseDataSourcesWrapper> eamCases;
/**
* Model for cells to display correlation case information
*/
CasesTableModel() {
eamCases = new ArrayList<>();
}
@Override
public int getColumnCount() {
return CaseTableColumns.values().length;
}
@Override
public int getRowCount() {
return eamCases.size();
}
@Override
public String getColumnName(int colIdx) {
return CaseTableColumns.values()[colIdx].columnName();
}
@Override
public Object getValueAt(int rowIdx, int colIdx) {
if (eamCases.isEmpty()) {
return Bundle.CasesTableModel_noData();
}
return mapValueById(rowIdx, CaseTableColumns.values()[colIdx]);
}
/**
* Map a rowIdx and colId to the value in that cell.
*
* @param rowIdx Index of row to search
* @param colId ID of column to search
*
* @return value in the cell
*/
@Messages({"CasesTableModel.noData=No Cases"})
private Object mapValueById(int rowIdx, CaseTableColumns colId) {
CaseDataSourcesWrapper eamCase = eamCases.get(rowIdx);
String value = Bundle.CasesTableModel_noData();
switch (colId) {
case CASE_NAME:
value = eamCase.getDisplayName();
break;
case CREATION_DATE:
value = eamCase.getCreationDate();
break;
default:
break;
}
return value;
}
@Override
public Class<String> getColumnClass(int colIdx) {
return String.class;
}
/**
* Add one local central repository case to the table.
*
* @param eamCase central repository case to add to the table
*/
void addEamCase(CorrelationCase eamCase, List<CorrelationDataSource> dataSourceList) {
eamCases.add(new CaseDataSourcesWrapper(eamCase, dataSourceList));
fireTableDataChanged();
}
/**
* Get the CaseDataSourcesWrapper for the specified index in the table.
*
* @param listIndex the idex of the object to get
*
* @return A caseDataSourcesWrapper containing the CorrelationCase and the
* CorrelationDataSources associated with it for the specified
* index.
*/
CaseDataSourcesWrapper getEamCase(int listIndex) {
return eamCases.get(listIndex);
}
/**
* Enum which lists columns of interest from CorrelationCase.
*/
@Messages({"CasesTableModel.case=Case Name",
"CasesTableModel.creationDate=Creation Date"})
private enum CaseTableColumns {
// Ordering here determines displayed column order in Content Viewer.
// If order is changed, update the CellRenderer to ensure correct row coloring.
CASE_NAME(Bundle.CasesTableModel_case()),
CREATION_DATE(Bundle.CasesTableModel_creationDate());
private final String columnName;
/**
* Make a DataSourceTableColumns enum item.
*
* @param columnName the name of the column.s
*/
CaseTableColumns(String columnName) {
this.columnName = columnName;
}
/**
* The name displayed in the column header.
*
* @return the name of the column.
*/
String columnName() {
return columnName;
}
}
}

View File

@ -0,0 +1,152 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
/**
* Model for cells to display correlation data source information
*/
class DataSourcesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
/**
* A list of correlation data sources from central repository.
*/
private final List<CorrelationDataSource> dataSources;
/**
* Create a new DataSourcesTableModel, with an initially empty list of data
* sources.
*/
DataSourcesTableModel() {
dataSources = new ArrayList<>();
}
@Override
public int getColumnCount() {
return DataSourcesTableColumns.values().length;
}
@Override
public int getRowCount() {
return dataSources.size();
}
@Override
public String getColumnName(int colIdx) {
return DataSourcesTableColumns.values()[colIdx].columnName();
}
@Override
public Object getValueAt(int rowIdx, int colIdx) {
if (dataSources.isEmpty()) {
return Bundle.DataSourcesTableModel_noData();
}
return mapValueById(rowIdx, DataSourcesTableColumns.values()[colIdx]);
}
/**
* Map a rowIdx and colId to the value in that cell.
*
* @param rowIdx Index of row to search
* @param colId ID of column to search
*
* @return value in the cell
*/
@Messages({"DataSourcesTableModel.noData=No Data Sources"})
private Object mapValueById(int rowIdx, DataSourcesTableColumns colId) {
CorrelationDataSource dataSource = dataSources.get(rowIdx);
String value = Bundle.DataSourcesTableModel_noData();
switch (colId) {
case DATA_SOURCE:
value = dataSource.getName();
break;
case DEVICE_ID:
value = dataSource.getDeviceID();
break;
default:
break;
}
return value;
}
@Override
public Class<String> getColumnClass(int colIdx) {
return String.class;
}
/**
* Add a list of datasources to the table.
*
* @param dataSourceList the list of datasources to add to the table
*/
void addDataSources(List<CorrelationDataSource> dataSourceList) {
dataSources.addAll(dataSourceList);
fireTableDataChanged();
}
/**
* Clear the data sources currently included in the model.
*/
void clearTable() {
dataSources.clear();
fireTableDataChanged();
}
@Messages({"DataSourcesTableModel.dataSource=Data Source Name",
"DataSourcesTableModel.deviceId=Device ID"})
/**
* Enum which lists columns of interest from CorrelationDataSource.
*/
private enum DataSourcesTableColumns {
// Ordering here determines displayed column order in Content Viewer.
// If order is changed, update the CellRenderer to ensure correct row coloring.
DATA_SOURCE(Bundle.DataSourcesTableModel_dataSource()),
DEVICE_ID(Bundle.DataSourcesTableModel_deviceId());
private final String columnName;
/**
* Make a CasesTableColumns enum item.
*
* @param columnName the name of the column.
*/
DataSourcesTableColumns(String columnName) {
this.columnName = columnName;
}
/**
* The name displayed in the column header.
*
* @return the name of the column.
*/
String columnName() {
return columnName;
}
}
}

View File

@ -441,7 +441,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private void showCasesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCasesButtonActionPerformed
store();
ShowCasesDialog showCasesDialog = new ShowCasesDialog();
ManageCasesDialog.displayManageCasesDialog();
}//GEN-LAST:event_showCasesButtonActionPerformed
@Override

View File

@ -0,0 +1,358 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 400]"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="casesSplitPane" alignment="1" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="casesSplitPane" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="casesSplitPane">
<Properties>
<Property name="dividerLocation" type="int" value="380"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="caseInfoPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="right"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="dataSourcesScrollPane" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="orgLabel" min="-2" pref="88" max="-2" attributes="0"/>
<Component id="caseNumberLabel" min="-2" pref="88" max="-2" attributes="0"/>
<Component id="examinerNameLabel" alignment="1" min="-2" pref="88" max="-2" attributes="0"/>
<Component id="examinerEmailLabel" alignment="1" min="-2" pref="88" max="-2" attributes="0"/>
<Component id="examinerPhoneLabel" alignment="1" min="-2" pref="88" max="-2" attributes="0"/>
</Group>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="caseNumberValueLabel" max="32767" attributes="0"/>
<Component id="orgValueLabel" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="examinerNameValueLabel" max="32767" attributes="0"/>
<Component id="examinerEmailValueLabel" max="32767" attributes="0"/>
<Component id="examinerPhoneValueLabel" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<Component id="notesLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="notesScrollPane" pref="428" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="caseInfoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesLabel" alignment="0" min="-2" pref="77" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="caseInfoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="orgLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="caseNumberLabel" max="32767" attributes="0"/>
<Component id="caseNumberValueLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="examinerNameLabel" max="32767" attributes="0"/>
<Component id="examinerNameValueLabel" max="32767" attributes="0"/>
</Group>
</Group>
<Component id="orgValueLabel" alignment="0" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="examinerEmailLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="examinerEmailValueLabel" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="examinerPhoneLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="examinerPhoneValueLabel" alignment="0" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="notesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="notesScrollPane" pref="55" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesScrollPane" pref="129" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="dataSourcesScrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="dataSourcesTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="dataSourcesTableModel" type="code"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="CaseManagerDialog_dataSourcesTable"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="notesScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="notesTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
</Property>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="3"/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="caseInfoLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.caseInfoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="dataSourcesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.dataSourcesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="notesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.notesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="orgLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.orgLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="caseNumberLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.caseNumberLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="examinerEmailLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.examinerEmailLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="examinerNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.examinerNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="examinerPhoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.examinerPhoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="orgValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="caseNumberValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="examinerNameValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="examinerEmailValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="examinerPhoneValueLabel">
</Component>
<Component class="javax.swing.JButton" name="closeButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.closeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[65, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[65, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[65, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="closeButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="casesPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="left"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="casesScrollPane" pref="379" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="casesScrollPane" pref="361" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="casesScrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="casesTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="casesTableModel" type="code"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,353 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.util.NbBundle.Messages;
/**
* A dialog which displays cases existing in the central repository and the
* central repo information associated with them.
*
*/
final class ManageCasesDialog extends javax.swing.JDialog {
private static final long serialVersionUID = 1L;
private final CasesTableModel casesTableModel = new CasesTableModel();
private final DataSourcesTableModel dataSourcesTableModel = new DataSourcesTableModel();
private final static Logger logger = Logger.getLogger(ManageCasesDialog.class.getName());
/**
* Creates new form ManageCasesDialog
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
@Messages({"ManageCasesDialog.title.text=Manage Cases"})
private ManageCasesDialog() {
super(WindowManager.getDefault().getMainWindow(), Bundle.ManageCasesDialog_title_text(),
true);
initComponents();
try {
EamDb dbManager = EamDb.getInstance();
Map<Integer, List<CorrelationDataSource>> dataSourcesByCaseId = new HashMap<>();
for (CorrelationDataSource dataSource : dbManager.getDataSources()) {
int caseID = dataSource.getCaseID();
List<CorrelationDataSource> dataSourceNames = dataSourcesByCaseId.getOrDefault(caseID, new ArrayList<>());
dataSourceNames.add(dataSource);
dataSourcesByCaseId.put(caseID, dataSourceNames);
}
for (CorrelationCase eamCase : dbManager.getCases()) {
casesTableModel.addEamCase(eamCase, dataSourcesByCaseId.getOrDefault(eamCase.getID(), new ArrayList<>()));
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
}
casesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
updateSelection();
}
}
});
//sort on first column by default
casesTable.getRowSorter().toggleSortOrder(0);
}
/**
* Create and display the Manage Cases dialog for the currently enabled
* central repository.
*/
static void displayManageCasesDialog() {
ManageCasesDialog caseInfoDialog = new ManageCasesDialog();
caseInfoDialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
caseInfoDialog.setVisible(true);
}
/**
* 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
casesSplitPane = new javax.swing.JSplitPane();
caseInfoPanel = new javax.swing.JPanel();
dataSourcesScrollPane = new javax.swing.JScrollPane();
dataSourcesTable = new javax.swing.JTable();
notesScrollPane = new javax.swing.JScrollPane();
notesTextArea = new javax.swing.JTextArea();
caseInfoLabel = new javax.swing.JLabel();
dataSourcesLabel = new javax.swing.JLabel();
notesLabel = new javax.swing.JLabel();
orgLabel = new javax.swing.JLabel();
caseNumberLabel = new javax.swing.JLabel();
examinerEmailLabel = new javax.swing.JLabel();
examinerNameLabel = new javax.swing.JLabel();
examinerPhoneLabel = new javax.swing.JLabel();
orgValueLabel = new javax.swing.JLabel();
caseNumberValueLabel = new javax.swing.JLabel();
examinerNameValueLabel = new javax.swing.JLabel();
examinerEmailValueLabel = new javax.swing.JLabel();
examinerPhoneValueLabel = new javax.swing.JLabel();
closeButton = new javax.swing.JButton();
casesPanel = new javax.swing.JPanel();
casesScrollPane = new javax.swing.JScrollPane();
casesTable = new javax.swing.JTable();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setMinimumSize(new java.awt.Dimension(400, 400));
casesSplitPane.setDividerLocation(380);
dataSourcesTable.setAutoCreateRowSorter(true);
dataSourcesTable.setModel(dataSourcesTableModel);
dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
dataSourcesScrollPane.setViewportView(dataSourcesTable);
notesScrollPane.setBorder(null);
notesTextArea.setEditable(false);
notesTextArea.setBackground(new java.awt.Color(240, 240, 240));
notesTextArea.setColumns(20);
notesTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
notesTextArea.setLineWrap(true);
notesTextArea.setRows(3);
notesTextArea.setWrapStyleWord(true);
notesTextArea.setBorder(null);
notesScrollPane.setViewportView(notesTextArea);
org.openide.awt.Mnemonics.setLocalizedText(caseInfoLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.caseInfoLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(dataSourcesLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.dataSourcesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(notesLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.notesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(orgLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.orgLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(caseNumberLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.caseNumberLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(examinerEmailLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerEmailLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(examinerNameLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerNameLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(examinerPhoneLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerPhoneLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.closeButton.text")); // NOI18N
closeButton.setMaximumSize(new java.awt.Dimension(65, 23));
closeButton.setMinimumSize(new java.awt.Dimension(65, 23));
closeButton.setPreferredSize(new java.awt.Dimension(65, 23));
closeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
closeButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout caseInfoPanelLayout = new javax.swing.GroupLayout(caseInfoPanel);
caseInfoPanel.setLayout(caseInfoPanelLayout);
caseInfoPanelLayout.setHorizontalGroup(
caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGap(6, 6, 6)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(orgLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(caseNumberLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(examinerNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(examinerEmailLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(examinerPhoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(caseNumberValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(orgValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGap(6, 6, 6)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(examinerNameValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(examinerEmailValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(examinerPhoneValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
.addComponent(notesLabel)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(notesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE))))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, caseInfoPanelLayout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(caseInfoLabel)
.addComponent(dataSourcesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
caseInfoPanelLayout.setVerticalGroup(
caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, caseInfoPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(caseInfoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addComponent(orgLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(caseNumberLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(caseNumberValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(examinerNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(examinerNameValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addComponent(orgValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(examinerEmailLabel))
.addComponent(examinerEmailValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(examinerPhoneLabel)
.addComponent(examinerPhoneValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(notesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(notesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 55, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
casesSplitPane.setRightComponent(caseInfoPanel);
casesTable.setAutoCreateRowSorter(true);
casesTable.setModel(casesTableModel);
casesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
casesScrollPane.setViewportView(casesTable);
javax.swing.GroupLayout casesPanelLayout = new javax.swing.GroupLayout(casesPanel);
casesPanel.setLayout(casesPanelLayout);
casesPanelLayout.setHorizontalGroup(
casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(casesPanelLayout.createSequentialGroup()
.addComponent(casesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 379, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
casesPanelLayout.setVerticalGroup(
casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(casesPanelLayout.createSequentialGroup()
.addComponent(casesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 361, Short.MAX_VALUE)
.addGap(40, 40, 40))
);
casesSplitPane.setLeftComponent(casesPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(casesSplitPane, javax.swing.GroupLayout.Alignment.TRAILING)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(casesSplitPane)
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
this.dispose();
}//GEN-LAST:event_closeButtonActionPerformed
/**
* Update the information displayed to reflect the currently selected case.
*/
private void updateSelection() {
dataSourcesTableModel.clearTable();
if (casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount()) {
CaseDataSourcesWrapper caseWrapper = casesTableModel.getEamCase(casesTable.convertRowIndexToModel(casesTable.getSelectedRow()));
orgValueLabel.setText(caseWrapper.getOrganizationName());
caseNumberValueLabel.setText(caseWrapper.getCaseNumber());
examinerNameValueLabel.setText(caseWrapper.getExaminerName());
examinerPhoneValueLabel.setText(caseWrapper.getExaminerPhone());
examinerEmailValueLabel.setText(caseWrapper.getExaminerEmail());
notesTextArea.setText(caseWrapper.getNotes());
dataSourcesTableModel.addDataSources(caseWrapper.getDataSources());
} else {
orgValueLabel.setText("");
caseNumberValueLabel.setText("");
examinerNameValueLabel.setText("");
examinerPhoneValueLabel.setText("");
examinerEmailValueLabel.setText("");
notesTextArea.setText("");
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel caseInfoLabel;
private javax.swing.JPanel caseInfoPanel;
private javax.swing.JLabel caseNumberLabel;
private javax.swing.JLabel caseNumberValueLabel;
private javax.swing.JPanel casesPanel;
private javax.swing.JScrollPane casesScrollPane;
private javax.swing.JSplitPane casesSplitPane;
private javax.swing.JTable casesTable;
private javax.swing.JButton closeButton;
private javax.swing.JLabel dataSourcesLabel;
private javax.swing.JScrollPane dataSourcesScrollPane;
private javax.swing.JTable dataSourcesTable;
private javax.swing.JLabel examinerEmailLabel;
private javax.swing.JLabel examinerEmailValueLabel;
private javax.swing.JLabel examinerNameLabel;
private javax.swing.JLabel examinerNameValueLabel;
private javax.swing.JLabel examinerPhoneLabel;
private javax.swing.JLabel examinerPhoneValueLabel;
private javax.swing.JLabel notesLabel;
private javax.swing.JScrollPane notesScrollPane;
private javax.swing.JTextArea notesTextArea;
private javax.swing.JLabel orgLabel;
private javax.swing.JLabel orgValueLabel;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[545, 415]"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="showCasesPanel" pref="1188" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="showCasesPanel" pref="473" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="showCasesPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[527, 407]"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="1188" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="showCasesScrollPane" alignment="0" pref="527" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="473" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="showCasesScrollPane" alignment="0" pref="407" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="showCasesScrollPane">
<Properties>
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[535, 415]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="outCasesPane">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="1423" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="innerCaseScrollPane" alignment="0" pref="1423" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="500" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="innerCaseScrollPane" alignment="0" pref="500" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="innerCaseScrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="caseDetailsTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="tableModel" type="code"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.caseDetailsTable.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="1"/>
</Property>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="closeButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="closeButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -1,190 +0,0 @@
/*
* Central Repository
*
* Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JDialog;
import javax.swing.JFrame;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Dialog to display table of CorrelationCase information from the CR tab of options.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class ShowCasesDialog extends JDialog {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(ShowCasesDialog.class.getName());
private final ShowCasesTableModel tableModel;
@Messages({"ShowCasesDialog.title_text=All Cases Details"})
/**
* Creates new form ShowCases Panel
*/
ShowCasesDialog() {
super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.ShowCasesDialog_title_text(),
true);
tableModel = new ShowCasesTableModel();
initComponents();
try {
EamDb dbManager = EamDb.getInstance();
List<CorrelationCase> eamCases = dbManager.getCases();
for(CorrelationCase eamCase : eamCases) {
tableModel.addEamCase(eamCase);
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
}
display();
}
private void display() {
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true);
}
/**
* 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
showCasesPanel = new javax.swing.JPanel();
showCasesScrollPane = new javax.swing.JScrollPane();
outCasesPane = new javax.swing.JPanel();
innerCaseScrollPane = new javax.swing.JScrollPane();
caseDetailsTable = new javax.swing.JTable();
closeButton = new javax.swing.JButton();
setTitle(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.title")); // NOI18N
setMinimumSize(new java.awt.Dimension(545, 415));
showCasesPanel.setPreferredSize(new java.awt.Dimension(527, 407));
showCasesScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
showCasesScrollPane.setPreferredSize(new java.awt.Dimension(535, 415));
innerCaseScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
caseDetailsTable.setAutoCreateRowSorter(true);
caseDetailsTable.setModel(tableModel);
caseDetailsTable.setToolTipText(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.caseDetailsTable.toolTipText")); // NOI18N
caseDetailsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
caseDetailsTable.getTableHeader().setReorderingAllowed(false);
innerCaseScrollPane.setViewportView(caseDetailsTable);
caseDetailsTable.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription")); // NOI18N
javax.swing.GroupLayout outCasesPaneLayout = new javax.swing.GroupLayout(outCasesPane);
outCasesPane.setLayout(outCasesPaneLayout);
outCasesPaneLayout.setHorizontalGroup(
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1423, Short.MAX_VALUE)
.addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1423, Short.MAX_VALUE))
);
outCasesPaneLayout.setVerticalGroup(
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 500, Short.MAX_VALUE)
.addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE))
);
showCasesScrollPane.setViewportView(outCasesPane);
javax.swing.GroupLayout showCasesPanelLayout = new javax.swing.GroupLayout(showCasesPanel);
showCasesPanel.setLayout(showCasesPanelLayout);
showCasesPanelLayout.setHorizontalGroup(
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1188, Short.MAX_VALUE)
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE))
);
showCasesPanelLayout.setVerticalGroup(
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 473, Short.MAX_VALUE)
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 407, Short.MAX_VALUE))
);
org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.text")); // NOI18N
closeButton.setActionCommand(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.actionCommand")); // NOI18N
closeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
closeButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1188, Short.MAX_VALUE)
.addGap(6, 6, 6))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(closeButton)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 473, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(closeButton)
.addContainerGap())
);
closeButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.AccessibleContext.accessibleName")); // NOI18N
pack();
}// </editor-fold>//GEN-END:initComponents
private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
dispose();
}//GEN-LAST:event_closeButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTable caseDetailsTable;
private javax.swing.JButton closeButton;
private javax.swing.JScrollPane innerCaseScrollPane;
private javax.swing.JPanel outCasesPane;
private javax.swing.JPanel showCasesPanel;
private javax.swing.JScrollPane showCasesScrollPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,187 +0,0 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
/**
* Model for cells to display correlation case information
*/
class ShowCasesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
@Messages({"ShowCasesTableModel.case=Case Name",
"ShowCasesTableModel.creationDate=Creation Date",
"ShowCasesTableModel.caseNumber=Case Number",
"ShowCasesTableModel.examinerName=Examiner Name",
"ShowCasesTableModel.examinerEmail=Examiner Email",
"ShowCasesTableModel.examinerPhone=Examiner Phone",
"ShowCasesTableModel.notes=Notes",
"ShowCasesTableModel.noData=No Cases"})
/**
* Enum which lists columns of interest from CorrelationCase.
*/
enum TableColumns {
// Ordering here determines displayed column order in Content Viewer.
// If order is changed, update the CellRenderer to ensure correct row coloring.
CASE_NAME(Bundle.ShowCasesTableModel_case(), 200),
CREATION_DATE(Bundle.ShowCasesTableModel_creationDate(), 150),
CASE_NUMBER(Bundle.ShowCasesTableModel_caseNumber(), 100),
EXAMINER_NAME(Bundle.ShowCasesTableModel_examinerName(), 200),
EXAMINER_EMAIL(Bundle.ShowCasesTableModel_examinerEmail(), 100),
EXAMINER_PHONE(Bundle.ShowCasesTableModel_examinerPhone(), 100),
NOTES(Bundle.ShowCasesTableModel_notes(), 450);
private final String columnName;
private final int columnWidth;
TableColumns(String columnName, int columnWidth) {
this.columnName = columnName;
this.columnWidth = columnWidth;
}
String columnName() {
return columnName;
}
int columnWidth() {
return columnWidth;
}
};
/**
* list of Eam Cases from central repository.
*/
private List<CorrelationCase> eamCases;
ShowCasesTableModel() {
eamCases = new ArrayList<>();
}
@Override
public int getColumnCount() {
return TableColumns.values().length;
}
/**
* Get the preferred width that has been configured for this column.
*
* A value of 0 means that no preferred width has been defined for this
* column.
*
* @param colIdx Column index
*
* @return preferred column width >= 0
*/
int getColumnPreferredWidth(int colIdx) {
return TableColumns.values()[colIdx].columnWidth();
}
@Override
public int getRowCount() {
return eamCases.size();
}
@Override
public String getColumnName(int colIdx) {
return TableColumns.values()[colIdx].columnName();
}
@Override
public Object getValueAt(int rowIdx, int colIdx) {
if (eamCases.isEmpty()) {
return Bundle.ShowCasesTableModel_noData();
}
return mapValueById(rowIdx, TableColumns.values()[colIdx]);
}
Object getRow(int rowIdx) {
return eamCases.get(rowIdx);
}
/**
* Map a rowIdx and colId to the value in that cell.
*
* @param rowIdx Index of row to search
* @param colId ID of column to search
*
* @return value in the cell
*/
private Object mapValueById(int rowIdx, TableColumns colId) {
CorrelationCase eamCase = eamCases.get(rowIdx);
String value = Bundle.ShowCasesTableModel_noData();
switch (colId) {
case CASE_NAME:
value = eamCase.getDisplayName();
break;
case CREATION_DATE:
value = eamCase.getCreationDate();
break;
case CASE_NUMBER:
value = eamCase.getCaseNumber();
break;
case EXAMINER_NAME:
value = eamCase.getExaminerName();
break;
case EXAMINER_EMAIL:
value = eamCase.getExaminerEmail();
break;
case EXAMINER_PHONE:
value = eamCase.getExaminerPhone();
break;
case NOTES:
value = eamCase.getNotes();
break;
default:
break;
}
return value;
}
@Override
public Class<String> getColumnClass(int colIdx) {
return String.class;
}
/**
* Add one local central repository case to the table.
*
* @param eamCase central repository case to add to the
* table
*/
void addEamCase(CorrelationCase eamCase) {
eamCases.add(eamCase);
fireTableDataChanged();
}
void clearTable() {
eamCases.clear();
fireTableDataChanged();
}
}

View File

@ -303,23 +303,25 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="endCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="endDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="startCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="startDatePicker" min="-2" max="-2" attributes="0"/>
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="endCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="endDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="startCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="startDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -124,7 +124,8 @@ final public class FiltersPanel extends JPanel {
updateFilters(true);
UserPreferences.addChangeListener(preferenceChangeEvent -> {
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) {
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME) ||
preferenceChangeEvent.getKey().equals(UserPreferences.TIME_ZONE_FOR_DISPLAYS)) {
updateTimeZone();
}
});
@ -175,7 +176,7 @@ final public class FiltersPanel extends JPanel {
}
private void updateTimeZone() {
dateRangeLabel.setText("Date Range ( " + Utils.getUserPreferredZoneId().toString() + "):");
dateRangeLabel.setText("Date Range (" + Utils.getUserPreferredZoneId().toString() + "):");
}
/**

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.communications;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.TimeZone;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
import org.sleuthkit.datamodel.Account;
@ -33,7 +34,8 @@ class Utils {
}
static ZoneId getUserPreferredZoneId() {
ZoneId zone = UserPreferences.displayTimesInLocalTime() ? ZoneOffset.systemDefault() : ZoneOffset.UTC;
ZoneId zone = UserPreferences.displayTimesInLocalTime() ?
ZoneOffset.systemDefault() : TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()).toZoneId();
return zone;
}

View File

@ -424,7 +424,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT count (*) as count FROM " + "\"" + tableName + "\"")) { //NON-NLS{
"SELECT count (*) as count FROM " + "\"" + tableName + "\"")) { //NON-NLS
numRows = resultSet.getInt("count");
numEntriesField.setText(numRows + " entries");
@ -442,9 +442,23 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
} else {
exportCsvButton.setEnabled(false);
nextPageButton.setEnabled(false);
selectedTableView.setupTable(Collections.emptyList());
}
//Execute a dummy SELECT * statement so that the metadata
//contains all column names
Map<String, Object> columnRow;
try (ResultSet metaDataResultSet = statement.executeQuery(
"SELECT * FROM " + "\"" + tableName + "\"")) {
//Column names are not found in the metadata of the result set
//above.
ResultSetMetaData metaData = metaDataResultSet.getMetaData();
columnRow = new LinkedHashMap<>();
for(int i = 1; i < metaData.getColumnCount(); i++){
columnRow.put(metaData.getColumnName(i), "");
}
}
selectedTableView.setupTable(Collections.singletonList(columnRow));
}
} catch (SQLException ex) {
logger.log(Level.SEVERE, String.format("Failed to load table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_selectTable_errorText(tableName));

View File

@ -24,6 +24,7 @@ import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import org.openide.util.NbPreferences;
import org.python.icu.util.TimeZone;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.TextConverterException;
@ -45,6 +46,7 @@ public final class UserPreferences {
public static final String HIDE_SLACK_FILES_IN_DATA_SRCS_TREE = "HideSlackFilesInDataSourcesTree"; //NON-NLS
public static final String HIDE_SLACK_FILES_IN_VIEWS_TREE = "HideSlackFilesInViewsTree"; //NON-NLS
public static final String DISPLAY_TIMES_IN_LOCAL_TIME = "DisplayTimesInLocalTime"; //NON-NLS
public static final String TIME_ZONE_FOR_DISPLAYS = "TimeZoneForDisplays"; //NON-NLS
public static final String NUMBER_OF_FILE_INGEST_THREADS = "NumberOfFileIngestThreads"; //NON-NLS
public static final String IS_MULTI_USER_MODE_ENABLED = "IsMultiUserModeEnabled"; //NON-NLS
public static final String EXTERNAL_DATABASE_HOSTNAME_OR_IP = "ExternalDatabaseHostnameOrIp"; //NON-NLS
@ -181,6 +183,14 @@ public final class UserPreferences {
public static void setDisplayTimesInLocalTime(boolean value) {
preferences.putBoolean(DISPLAY_TIMES_IN_LOCAL_TIME, value);
}
public static String getTimeZoneForDisplays() {
return preferences.get(TIME_ZONE_FOR_DISPLAYS, TimeZone.GMT_ZONE.getID());
}
public static void setTimeZoneForDisplays(String timeZone) {
preferences.put(TIME_ZONE_FOR_DISPLAYS, timeZone);
}
public static int numberOfFileIngestThreads() {
return preferences.getInt(NUMBER_OF_FILE_INGEST_THREADS, 2);

View File

@ -180,7 +180,6 @@ ViewPreferencesPanel.useBestViewerRadioButton.text=Change to the most specific f
ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=For example, stay in Hex view when a JPEG is selected.
ViewPreferencesPanel.keepCurrentViewerRadioButton.text=Stay on the same file viewer
ViewPreferencesPanel.useLocalTimeRadioButton.text=Use local time zone
ViewPreferencesPanel.useGMTTimeRadioButton.text=Use GMT
ViewPreferencesPanel.dataSourcesHideKnownCheckbox.text=Data Sources area (the directory hierarchy)
ViewPreferencesPanel.viewsHideKnownCheckbox.text=Views area
ViewPreferencesPanel.dataSourcesHideSlackCheckbox.text=Data Sources area (the directory hierarchy)
@ -192,3 +191,4 @@ ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for:
ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns to reduce loading times
ViewPreferencesPanel.deletedFilesLimitCheckbox.text=Limit to 10,000
ViewPreferencesPanel.deletedFilesLimitLabel.text=Limit number of deleted files displayed:
ViewPreferencesPanel.useAnotherTimeRadioButton.text=Use another time zone

View File

@ -128,6 +128,5 @@ ViewPreferencesPanel.useBestViewerRadioButton.text=\u6700\u3082\u5c02\u9580\u768
ViewPreferencesPanel.keepCurrentViewerRadioButton.text=\u305d\u306e\u307e\u307e\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u3092\u4f7f\u7528
ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u305d\u306e\u307e\u307eHEX\u30d3\u30e5\u30fc\u3092\u4f7f\u7528\u3002
ViewPreferencesPanel.useLocalTimeRadioButton.text=\u30ed\u30fc\u30ab\u30eb\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u4f7f\u7528
ViewPreferencesPanel.useGMTTimeRadioButton.text=GMT\u3092\u4f7f\u7528
ViewPreferencesPanel.dataSourcesHideKnownCheckbox.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30a8\u30ea\u30a2\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u968e\u5c64\uff09
ViewPreferencesPanel.viewsHideKnownCheckbox.text=\u30d3\u30e5\u30fc\u30a8\u30ea\u30a2

View File

@ -487,7 +487,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID())
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID())) {
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID())
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID())) {
return 3;
} else {
return 6;

View File

@ -40,6 +40,7 @@ public final class TextPrompt extends JLabel
public TextPrompt(String text, JTextComponent component, Show show) {
this.component = component;
component.removeAll();
setShow(show);
document = component.getDocument();

View File

@ -31,11 +31,19 @@
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 452]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="viewPreferencesPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 452]"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
@ -87,57 +95,68 @@
<Group type="103" groupAlignment="0" attributes="0">
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="deletedFilesLimitCheckbox" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="399" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="135" max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="272" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hideKnownFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hideKnownFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="hideSlackFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Component id="hideSlackFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="displayTimeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="keepCurrentViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useBestViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="displayTimeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="keepCurrentViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useBestViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useAnotherTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" alignment="0" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="centralRepoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" alignment="0" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="10" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -158,6 +177,16 @@
<Component id="dataSourcesHideSlackCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="viewsHideSlackCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
@ -169,20 +198,12 @@
<Component id="displayTimeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useAnotherTimeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="67" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" min="-2" pref="33" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
@ -295,14 +316,14 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useLocalTimeRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="useGMTTimeRadioButton">
<Component class="javax.swing.JRadioButton" name="useAnotherTimeRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.useGMTTimeRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.useAnotherTimeRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useGMTTimeRadioButtonActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useAnotherTimeRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="hideOtherUsersTagsCheckbox">
@ -356,6 +377,28 @@
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="timeZoneList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="timeZoneListValueChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="currentCaseSettingsPanel">

View File

@ -19,12 +19,14 @@
package org.sleuthkit.autopsy.corecomponents;
import java.util.Objects;
import java.util.TimeZone;
import javax.swing.JPanel;
import org.netbeans.spi.options.OptionsPanelController;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
@ -44,6 +46,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
public ViewPreferencesPanel(boolean immediateUpdates) {
initComponents();
this.immediateUpdates = immediateUpdates;
this.timeZoneList.setListData(TimeZoneUtils.createTimeZoneList().stream().toArray(String[]::new));
}
@Override
@ -54,8 +58,10 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
useBestViewerRadioButton.setSelected(!keepPreferredViewer);
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
timeZoneList.setEnabled(!useLocalTime);
timeZoneList.setSelectedValue(TimeZoneUtils.createTimeZoneString(TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays())), true);
useLocalTimeRadioButton.setSelected(useLocalTime);
useGMTTimeRadioButton.setSelected(!useLocalTime);
useAnotherTimeRadioButton.setSelected(!useLocalTime);
dataSourcesHideKnownCheckbox.setSelected(UserPreferences.hideKnownFilesInDataSourcesTree());
viewsHideKnownCheckbox.setSelected(UserPreferences.hideKnownFilesInViewsTree());
@ -84,6 +90,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
public void store() {
UserPreferences.setKeepPreferredContentViewer(keepCurrentViewerRadioButton.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRadioButton.isSelected());
if (useAnotherTimeRadioButton.isSelected()) {
UserPreferences.setTimeZoneForDisplays(timeZoneList.getSelectedValue().substring(11).trim());
}
UserPreferences.setHideKnownFilesInDataSourcesTree(dataSourcesHideKnownCheckbox.isSelected());
UserPreferences.setHideKnownFilesInViewsTree(viewsHideKnownCheckbox.isSelected());
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCheckbox.isSelected());
@ -135,19 +144,24 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
viewsHideSlackCheckbox = new javax.swing.JCheckBox();
displayTimeLabel = new javax.swing.JLabel();
useLocalTimeRadioButton = new javax.swing.JRadioButton();
useGMTTimeRadioButton = new javax.swing.JRadioButton();
useAnotherTimeRadioButton = new javax.swing.JRadioButton();
hideOtherUsersTagsCheckbox = new javax.swing.JCheckBox();
hideOtherUsersTagsLabel = new javax.swing.JLabel();
commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox();
centralRepoLabel = new javax.swing.JLabel();
deletedFilesLimitCheckbox = new javax.swing.JCheckBox();
deletedFilesLimitLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
timeZoneList = new javax.swing.JList<>();
currentCaseSettingsPanel = new javax.swing.JPanel();
groupByDataSourceCheckbox = new javax.swing.JCheckBox();
currentSessionSettingsPanel = new javax.swing.JPanel();
hideRejectedResultsCheckbox = new javax.swing.JCheckBox();
viewPreferencesScrollPane.setBorder(null);
viewPreferencesScrollPane.setPreferredSize(new java.awt.Dimension(625, 452));
viewPreferencesPanel.setPreferredSize(new java.awt.Dimension(625, 452));
globalSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.globalSettingsPanel.border.title"))); // NOI18N
@ -210,10 +224,10 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
});
org.openide.awt.Mnemonics.setLocalizedText(useGMTTimeRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.useGMTTimeRadioButton.text")); // NOI18N
useGMTTimeRadioButton.addActionListener(new java.awt.event.ActionListener() {
org.openide.awt.Mnemonics.setLocalizedText(useAnotherTimeRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.useAnotherTimeRadioButton.text")); // NOI18N
useAnotherTimeRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useGMTTimeRadioButtonActionPerformed(evt);
useAnotherTimeRadioButtonActionPerformed(evt);
}
});
@ -244,6 +258,13 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitLabel.text")); // NOI18N
timeZoneList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
timeZoneListValueChanged(evt);
}
});
jScrollPane1.setViewportView(timeZoneList);
javax.swing.GroupLayout globalSettingsPanelLayout = new javax.swing.GroupLayout(globalSettingsPanel);
globalSettingsPanel.setLayout(globalSettingsPanelLayout);
globalSettingsPanelLayout.setHorizontalGroup(
@ -256,41 +277,48 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(commentsOccurencesColumnsCheckbox)
.addComponent(hideOtherUsersTagsCheckbox)
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(399, 399, 399))))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(centralRepoLabel)
.addGap(135, 135, 135)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hideKnownFilesLabel)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hideKnownFilesLabel)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideSlackCheckbox)
.addComponent(viewsHideSlackCheckbox)))
.addComponent(hideSlackFilesLabel))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideKnownCheckbox)
.addComponent(viewsHideKnownCheckbox)))))
.addGap(18, 18, 18)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(displayTimeLabel)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideSlackCheckbox)
.addComponent(viewsHideSlackCheckbox)))
.addComponent(hideSlackFilesLabel))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideKnownCheckbox)
.addComponent(viewsHideKnownCheckbox)))))
.addGap(18, 18, 18)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(displayTimeLabel)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(keepCurrentViewerRadioButton)
.addComponent(useBestViewerRadioButton)
.addComponent(useGMTTimeRadioButton)
.addComponent(useLocalTimeRadioButton)))
.addComponent(selectFileLabel)))
.addComponent(hideOtherUsersTagsLabel)
.addComponent(centralRepoLabel)
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 10, Short.MAX_VALUE)))
.addContainerGap())
.addComponent(keepCurrentViewerRadioButton)
.addComponent(useBestViewerRadioButton)
.addComponent(useLocalTimeRadioButton)
.addComponent(useAnotherTimeRadioButton)))
.addComponent(selectFileLabel)))
.addComponent(hideOtherUsersTagsLabel)
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())))
);
globalSettingsPanelLayout.setVerticalGroup(
globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -308,7 +336,17 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesHideSlackCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(viewsHideSlackCheckbox))
.addComponent(viewsHideSlackCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(hideOtherUsersTagsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(hideOtherUsersTagsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(centralRepoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(commentsOccurencesColumnsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(deletedFilesLimitLabel))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(selectFileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -320,17 +358,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useLocalTimeRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useGMTTimeRadioButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(hideOtherUsersTagsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(hideOtherUsersTagsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(centralRepoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(commentsOccurencesColumnsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(deletedFilesLimitLabel)
.addComponent(useAnotherTimeRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0))
@ -415,11 +445,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(viewPreferencesScrollPane)
.addComponent(viewPreferencesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(viewPreferencesScrollPane)
.addComponent(viewPreferencesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@ -445,7 +475,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private void useLocalTimeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useLocalTimeRadioButtonActionPerformed
useLocalTimeRadioButton.setSelected(true);
useGMTTimeRadioButton.setSelected(false);
useAnotherTimeRadioButton.setSelected(false);
timeZoneList.setEnabled(false);
if (immediateUpdates) {
UserPreferences.setDisplayTimesInLocalTime(true);
} else {
@ -453,15 +484,16 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
}//GEN-LAST:event_useLocalTimeRadioButtonActionPerformed
private void useGMTTimeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useGMTTimeRadioButtonActionPerformed
private void useAnotherTimeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useAnotherTimeRadioButtonActionPerformed
useLocalTimeRadioButton.setSelected(false);
useGMTTimeRadioButton.setSelected(true);
useAnotherTimeRadioButton.setSelected(true);
timeZoneList.setEnabled(true);
if (immediateUpdates) {
UserPreferences.setDisplayTimesInLocalTime(false);
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_useGMTTimeRadioButtonActionPerformed
}//GEN-LAST:event_useAnotherTimeRadioButtonActionPerformed
private void dataSourcesHideKnownCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideKnownCheckboxActionPerformed
if (immediateUpdates) {
@ -535,6 +567,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
}//GEN-LAST:event_deletedFilesLimitCheckboxActionPerformed
private void timeZoneListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_timeZoneListValueChanged
if (immediateUpdates && useAnotherTimeRadioButton.isSelected()) {
UserPreferences.setTimeZoneForDisplays(timeZoneList.getSelectedValue().substring(11).trim());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_timeZoneListValueChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel centralRepoLabel;
@ -553,10 +593,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private javax.swing.JLabel hideOtherUsersTagsLabel;
private javax.swing.JCheckBox hideRejectedResultsCheckbox;
private javax.swing.JLabel hideSlackFilesLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRadioButton;
private javax.swing.JLabel selectFileLabel;
private javax.swing.JList<String> timeZoneList;
private javax.swing.JRadioButton useAnotherTimeRadioButton;
private javax.swing.JRadioButton useBestViewerRadioButton;
private javax.swing.JRadioButton useGMTTimeRadioButton;
private javax.swing.JRadioButton useLocalTimeRadioButton;
private javax.swing.JPanel viewPreferencesPanel;
private javax.swing.JScrollPane viewPreferencesScrollPane;

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2015 Basis Technology Corp.
* Copyright 2012-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,14 +18,22 @@
*/
package org.sleuthkit.autopsy.coreutils;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
public class NetworkUtils {
private NetworkUtils() {
}
/**
* Set the host name variable. Sometimes the network can be finicky, so the
* answer returned by getHostName() could throw an exception or be null.
* Have it read the environment variable if getHostName() is unsuccessful.
*
* @return the local host name
*/
public static String getLocalHostName() {
String hostName = "";
@ -41,4 +49,78 @@ public class NetworkUtils {
}
return hostName;
}
/**
* Attempt to manually extract the domain from a URL.
*
* @param url
* @return empty string if no domain could be found
*/
private static String getBaseDomain(String url) {
String host = null;
//strip protocol
String cleanUrl = url.replaceFirst(".*:\\/\\/", "");
//strip after slashes
String dirToks[] = cleanUrl.split("\\/");
if (dirToks.length > 0) {
host = dirToks[0];
} else {
host = cleanUrl;
}
//get the domain part from host (last 2)
StringTokenizer tok = new StringTokenizer(host, ".");
StringBuilder hostB = new StringBuilder();
int toks = tok.countTokens();
for (int count = 0; count < toks; ++count) {
String part = tok.nextToken();
int diff = toks - count;
if (diff < 3) {
hostB.append(part);
}
if (diff == 2) {
hostB.append(".");
}
}
String base = hostB.toString();
// verify there are no special characters in there
if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) {
return "";
}
return base;
}
/**
* Attempt to extract the domain from a URL.
* Will start by using the built-in URL class, and if that fails will
* try to extract it manually.
*
* @param urlString The URL to extract the domain from
* @return empty string if no domain name was found
*/
public static String extractDomain(String urlString) {
if (urlString == null) {
return "";
}
String result = "";
try {
URL url = new URL(urlString);
result = url.getHost();
} catch (MalformedURLException ex) {
//do not log if not a valid URL - we will try to extract it ourselves
}
//was not a valid URL, try a less picky method
if (result == null || result.trim().isEmpty()) {
return getBaseDomain(urlString);
}
return result;
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -20,7 +20,13 @@ package org.sleuthkit.autopsy.coreutils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
/**
* Utility methods for workig with time zones.
@ -41,7 +47,7 @@ public class TimeZoneUtils {
java.util.TimeZone zone = java.util.TimeZone.getTimeZone(timeZoneId);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int min = (offset % 3600) / 60;
int min = Math.abs((offset % 3600) / 60);
DateFormat dfm = new SimpleDateFormat("z");
dfm.setTimeZone(zone);
@ -59,6 +65,73 @@ public class TimeZoneUtils {
return result;
}
/**
* Generate a time zone string containing the GMT offset and ID.
*
* @param timeZone The time zone.
*
* @return The time zone string.
*/
public static String createTimeZoneString(TimeZone timeZone) {
int offset = timeZone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = Math.abs((offset % 3600) / 60);
return String.format("(GMT%+d:%02d) %s", hour, minutes, timeZone.getID()); //NON-NLS
}
/**
* Generates a list of time zones.
*/
public static List<String> createTimeZoneList() {
/*
* Create a list of time zones.
*/
List<TimeZone> timeZoneList = new ArrayList<>();
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneList.add(TimeZone.getTimeZone(id));
}
/*
* Sort the list of time zones first by offset, then by ID.
*/
Collections.sort(timeZoneList, new Comparator<TimeZone>(){
@Override
public int compare(TimeZone o1, TimeZone o2){
int offsetDelta = Integer.compare(o1.getRawOffset(), o2.getRawOffset());
if (offsetDelta == 0) {
return o1.getID().compareToIgnoreCase(o2.getID());
}
return offsetDelta;
}
});
/*
* Create a list of Strings encompassing both the GMT offset and the
* time zone ID.
*/
List<String> outputList = new ArrayList<>();
for (TimeZone timeZone : timeZoneList) {
outputList.add(createTimeZoneString(timeZone));
}
return outputList;
}
/**
* Prevents instantiation.

View File

@ -145,7 +145,7 @@ public final class ContentUtils {
try {
if (!shouldDisplayTimesInLocalTime()) {
return TimeZone.getTimeZone("GMT");
return TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays());
} else {
final Content dataSource = content.getDataSource();
if ((dataSource != null) && (dataSource instanceof Image)) {

View File

@ -20,8 +20,7 @@ package org.sleuthkit.autopsy.datasourceprocessors;
import java.io.File;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
@ -32,6 +31,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
/**
* Allows examiner to supply a raw data source.
@ -82,26 +82,13 @@ final class RawDSInputPanel extends JPanel implements DocumentListener {
* machine time zone to be selected.
*/
private void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
timeZoneComboBox.addItem(item);
List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
for (String timeZone : timeZoneList) {
timeZoneComboBox.addItem(timeZone);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}
/**

View File

@ -167,6 +167,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
public void preferenceChange(PreferenceChangeEvent evt) {
switch (evt.getKey()) {
case UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME:
case UserPreferences.TIME_ZONE_FOR_DISPLAYS:
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES:

View File

@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SimpleTimeZone;
@ -44,6 +43,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
/**
* Filters file date properties (modified/created/etc.. times)
@ -144,30 +144,15 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
Case currentCase = Case.getCurrentCaseThrows(); // get the most updated case
Set<TimeZone> caseTimeZones = currentCase.getTimeZones();
Iterator<TimeZone> iterator = caseTimeZones.iterator();
while (iterator.hasNext()) {
TimeZone zone = iterator.next();
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, zone.getID()); //NON-NLS
timeZones.add(item);
for (TimeZone timeZone : caseTimeZones) {
timeZones.add(TimeZoneUtils.createTimeZoneString(timeZone));
}
if (caseTimeZones.size() > 0) {
timeZones.add(SEPARATOR);
}
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); //NON-NLS
timeZones.add(item);
}
timeZones.addAll(TimeZoneUtils.createTimeZoneList());
} catch (NoCurrentCaseException ex) {
// No current case.
}

View File

@ -269,8 +269,7 @@ class MSOfficeEmbeddedContentExtractor {
HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af));
PicturesTable pictureTable = doc.getPicturesTable();
listOfAllPictures = pictureTable.getAllPictures();
} catch (IOException | IllegalArgumentException
| IndexOutOfBoundsException | NullPointerException ex) {
} catch (Exception ex) {
// IOException:
// Thrown when the document has issues being read.
@ -286,10 +285,9 @@ class MSOfficeEmbeddedContentExtractor {
// These get thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS
//Any runtime exception escaping
LOGGER.log(Level.WARNING, "Word document container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
return null;
}
@ -333,8 +331,7 @@ class MSOfficeEmbeddedContentExtractor {
try {
HSLFSlideShow ppt = new HSLFSlideShow(new ReadContentInputStream(af));
listOfAllPictures = ppt.getPictureData();
} catch (IOException | IllegalArgumentException
| IndexOutOfBoundsException ex) {
} catch (Exception ex) {
// IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the
// document version is unsupported. The IllegalArgumentException may
@ -346,10 +343,7 @@ class MSOfficeEmbeddedContentExtractor {
// This gets thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS
LOGGER.log(Level.WARNING, "PPT container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
return null;
}
@ -422,9 +416,7 @@ class MSOfficeEmbeddedContentExtractor {
try {
Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af));
listOfAllPictures = xls.getAllPictures();
} catch (IOException | LeftoverDataException
| RecordFormatException | IllegalArgumentException
| IndexOutOfBoundsException ex) {
} catch (Exception ex) {
// IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the
// document version is unsupported. The IllegalArgumentException may
@ -443,10 +435,7 @@ class MSOfficeEmbeddedContentExtractor {
// These get thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
LOGGER.log(Level.SEVERE, String.format("%s%s", NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()), af.getName()), ex); //NON-NLS
LOGGER.log(Level.WARNING, "Excel (.xls) document container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
return null;
}

View File

@ -180,6 +180,15 @@ class SevenZipExtractor {
* @return true if potential zip bomb, false otherwise
*/
private boolean isZipBombArchiveItemCheck(AbstractFile archiveFile, ISevenZipInArchive inArchive, int inArchiveItemIndex, ConcurrentHashMap<Long, Archive> depthMap, String escapedFilePath) {
//If a file is corrupted as a result of reconstructing it from unallocated space, then
//7zip does a poor job estimating the original uncompressed file size.
//As a result, many corrupted files have wonky compression ratios and could flood the UI
//with false zip bomb notifications. The decision was made to skip compression ratio checks
//for unallocated zip files. Instead, we let the depth be an indicator of a zip bomb.
if(archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) {
return false;
}
try {
final Long archiveItemSize = (Long) inArchive.getProperty(
inArchiveItemIndex, PropID.SIZE);
@ -540,7 +549,6 @@ class SevenZipExtractor {
inArchive = SevenZip.openInArchive(options, stream, password);
}
numItems = inArchive.getNumberOfItems();
logger.log(Level.INFO, "Count of items in archive: {0}: {1}", new Object[]{escapedArchiveFilePath, numItems}); //NON-NLS
progress.start(numItems);
progressStarted = true;

View File

@ -28,6 +28,7 @@ import com.healthmarketscience.jackcess.util.MemFileChannel;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.BufferUnderflowException;
import java.util.logging.Level;
import org.apache.tika.exception.EncryptedDocumentException;
import org.apache.tika.exception.TikaException;
@ -313,7 +314,12 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
DatabaseBuilder databaseBuilder = new DatabaseBuilder();
databaseBuilder.setChannel(memFileChannel);
databaseBuilder.setCodecProvider(codecProvider);
Database accessDatabase = databaseBuilder.open();
Database accessDatabase;
try {
accessDatabase = databaseBuilder.open();
} catch (IOException | BufferUnderflowException | IndexOutOfBoundsException ignored) {
return passwordProtected;
}
/*
* No exception has been thrown at this point, so the file
* is either a JET database, or an unprotected ACE database.

View File

@ -91,7 +91,7 @@ HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg=Failed to open has
HashLookupModuleFactory.moduleName.text=Hash Lookup
HashLookupModuleFactory.moduleDescription.text=Identifies known and notable files using supplied hash sets, such as a standard NSRL hash set.
HashDbIngestModule.fileReadErrorMsg=Read Error\: {0}
HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0}.
HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0} ({1}).
HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error\: {0}
HashDbIngestModule.settingKnownBadStateErr=Error encountered while setting notable state for {0}.
HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.

View File

@ -227,7 +227,9 @@ public class HashDbIngestModule implements FileIngestModule {
services.postMessage(IngestMessage.createErrorMessage(
HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(), "HashDbIngestModule.fileReadErrorMsg", name),
NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr", name)));
NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr",
file.getParentPath() + file.getName(),
file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)?"Allocated File" : "Deleted File")));
return ProcessResult.ERROR;
}
}

View File

@ -648,6 +648,15 @@ public final class FilesSet implements Serializable {
AbstractTextCondition(Pattern regex) {
this.textMatcher = new FilesSet.Rule.RegexMatcher(regex);
}
/**
* Construct a case-insensitive multi-value text condition.
*
* @param values The list of values in which to look for a match.
*/
AbstractTextCondition(List<String> values) {
this.textMatcher = new FilesSet.Rule.CaseInsensitiveMultiValueStringComparisionMatcher(values);
}
/**
* Get the text the condition matches.
@ -820,11 +829,11 @@ public final class FilesSet implements Serializable {
*
* @param extension The file name extension to be matched.
*/
public ExtensionCondition(String extension) {
public ExtensionCondition(List<String> extensions) {
// If there is a leading ".", strip it since
// AbstractFile.getFileNameExtension() returns just the
// extension chars and not the dot.
super(extension.startsWith(".") ? extension.substring(1) : extension, false);
super(extensions);
}
/**
@ -948,6 +957,60 @@ public final class FilesSet implements Serializable {
}
}
/**
* A text matcher that looks for a single case-insensitive string match
* in a multi-value list.
*/
private static class CaseInsensitiveMultiValueStringComparisionMatcher implements TextMatcher {
private static final long serialVersionUID = 1L;
private final List<String> valuesToMatch;
/**
* Construct a text matcher that looks for a single case-insensitive
* string match in a multi-value list.
*
* @param valuesToMatch The list of values in which to look for a
* match.
*/
CaseInsensitiveMultiValueStringComparisionMatcher(List<String> valuesToMatch) {
List<String> values = new ArrayList<>(valuesToMatch);
for (int i=0; i < values.size(); i++) {
// Remove leading and trailing whitespace.
String tempValue = values.get(i).trim();
// Strip "." from the start of the extension if it exists.
if (tempValue.startsWith(".")) {
tempValue = tempValue.substring(1);
}
values.set(i, tempValue);
}
this.valuesToMatch = values;
}
@Override
public String getTextToMatch() {
return String.join(",", this.valuesToMatch);
}
@Override
public boolean isRegex() {
return false;
}
@Override
public boolean textMatches(String subject) {
for (String value : valuesToMatch) {
if (value.equalsIgnoreCase(subject)) {
return true;
}
}
return false;
}
}
/**
* A text matcher that does regular expression matching.
*/

View File

@ -29,7 +29,7 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" pref="800" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@ -173,7 +173,7 @@
<Component id="deleteRuleButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="24" pref="47" max="32767" attributes="0"/>
<EmptySpace min="24" max="32767" attributes="0"/>
</Group>
</Group>
</Group>

View File

@ -960,7 +960,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
.addComponent(editRuleButton)
.addGap(18, 18, 18)
.addComponent(deleteRuleButton)))
.addGap(24, 47, Short.MAX_VALUE))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
);
jPanel1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {copySetButton, deleteSetButton, editSetButton, exportSetButton, importSetButton, newSetButton});
@ -1060,7 +1060,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

View File

@ -47,22 +47,23 @@
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="ruleNameTextField" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="daysIncludedTextField" min="-2" pref="69" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="daysIncludedLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="ruleNameTextField" pref="249" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="fullNameRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="extensionRadioButton" min="-2" pref="98" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="nameRegexCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="fullNameRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="extensionRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="nameRegexCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
@ -205,6 +206,9 @@
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fullNameRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="extensionRadioButton">
<Properties>
@ -216,6 +220,9 @@
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="extensionRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="nameRegexCheckbox">
<Properties>

View File

@ -18,7 +18,9 @@
*/
package org.sleuthkit.autopsy.modules.interestingitems;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
import java.util.logging.Level;
@ -31,6 +33,7 @@ import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponents.TextPrompt;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TYPE;
@ -46,6 +49,8 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
"FilesSetRulePanel.kiloBytes=Kilobytes",
"FilesSetRulePanel.megaBytes=Megabytes",
"FilesSetRulePanel.gigaBytes=Gigabytes",
"FilesSetRulePanel.nameTextField.fullNameExample=Example: \"file.exe\"",
"FilesSetRulePanel.nameTextField.extensionExample=Examples: \"jpg\" or \"jpg,jpeg,gif\"",
"FilesSetRulePanel.NoConditionError=Must have at least one condition to make a rule.",
"FilesSetRulePanel.NoMimeTypeError=Please select a valid MIME type.",
"FilesSetRulePanel.NoNameError=Name cannot be empty",
@ -62,6 +67,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
private static final List<String> ILLEGAL_FILE_PATH_CHARS = FilesSetsManager.getIllegalFilePathChars();
private JButton okButton;
private JButton cancelButton;
private TextPrompt nameTextFieldPrompt;
/**
* Constructs a files set rule panel in create rule mode.
@ -87,6 +93,8 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
this.dateCheckActionPerformed(null);
populateComponentsWithDefaultValues();
this.setButtons(okButton, cancelButton);
updateNameTextFieldPrompt();
}
/**
@ -120,6 +128,34 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
populatePathConditionComponents(rule);
populateDateConditionComponents(rule);
this.setButtons(okButton, cancelButton);
updateNameTextFieldPrompt();
}
/**
* Update the text prompt of the name text field based on the input type
* selection.
*/
private void updateNameTextFieldPrompt() {
/**
* Add text prompt to the text field.
*/
String text;
if (fullNameRadioButton.isSelected()) {
text = Bundle.FilesSetRulePanel_nameTextField_fullNameExample();
} else {
text = Bundle.FilesSetRulePanel_nameTextField_extensionExample();
}
nameTextFieldPrompt = new TextPrompt(text, nameTextField);
/**
* Sets the foreground color and transparency of the text prompt.
*/
nameTextFieldPrompt.setForeground(Color.LIGHT_GRAY);
nameTextFieldPrompt.changeAlpha(0.9f); // Mostly opaque
validate();
repaint();
}
/**
@ -435,7 +471,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
if (!this.nameTextField.getText().isEmpty()) {
if (this.nameRegexCheckbox.isSelected()) {
try {
Pattern pattern = Pattern.compile(this.nameTextField.getText());
Pattern pattern = Pattern.compile(this.nameTextField.getText(), Pattern.CASE_INSENSITIVE);
if (this.fullNameRadioButton.isSelected()) {
condition = new FilesSet.Rule.FullNameCondition(pattern);
} else {
@ -449,7 +485,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
if (this.fullNameRadioButton.isSelected()) {
condition = new FilesSet.Rule.FullNameCondition(this.nameTextField.getText());
} else {
condition = new FilesSet.Rule.ExtensionCondition(this.nameTextField.getText());
condition = new FilesSet.Rule.ExtensionCondition(Arrays.asList(this.nameTextField.getText().split(",")));
}
} else {
logger.log(Level.SEVERE, "Attempt to get name condition with illegal chars"); // NON-NLS
@ -520,7 +556,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
if (!this.pathTextField.getText().isEmpty()) {
if (this.pathRegexCheckBox.isSelected()) {
try {
condition = new FilesSet.Rule.ParentPathCondition(Pattern.compile(this.pathTextField.getText()));
condition = new FilesSet.Rule.ParentPathCondition(Pattern.compile(this.pathTextField.getText(), Pattern.CASE_INSENSITIVE));
} catch (PatternSyntaxException ex) {
logger.log(Level.SEVERE, "Attempt to get malformed path condition", ex); // NON-NLS
throw new IllegalStateException("The files set rule panel path condition is not in a valid state"); // NON-NLS
@ -657,10 +693,20 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
nameButtonGroup.add(fullNameRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(fullNameRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.fullNameRadioButton.text")); // NOI18N
fullNameRadioButton.setEnabled(false);
fullNameRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fullNameRadioButtonActionPerformed(evt);
}
});
nameButtonGroup.add(extensionRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(extensionRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.extensionRadioButton.text")); // NOI18N
extensionRadioButton.setEnabled(false);
extensionRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
extensionRadioButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(nameRegexCheckbox, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.nameRegexCheckbox.text")); // NOI18N
nameRegexCheckbox.setEnabled(false);
@ -782,18 +828,19 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
.addComponent(pathSeparatorInfoLabel))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ruleNameTextField)
.addGroup(layout.createSequentialGroup()
.addComponent(daysIncludedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(daysIncludedLabel))
.addComponent(ruleNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 249, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(fullNameRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(extensionRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 98, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(nameRegexCheckbox)))
.addGap(1, 1, 1))))
.addComponent(daysIncludedLabel)
.addGap(0, 0, Short.MAX_VALUE)))
.addGap(1, 1, 1))
.addGroup(layout.createSequentialGroup()
.addComponent(fullNameRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(extensionRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(nameRegexCheckbox))))
.addComponent(jLabel5)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -952,6 +999,14 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
this.setOkButton();
}//GEN-LAST:event_mimeCheckActionPerformed
private void extensionRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_extensionRadioButtonActionPerformed
updateNameTextFieldPrompt();
}//GEN-LAST:event_extensionRadioButtonActionPerformed
private void fullNameRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fullNameRadioButtonActionPerformed
updateNameTextFieldPrompt();
}//GEN-LAST:event_fullNameRadioButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton allRadioButton;
private javax.swing.JCheckBox dateCheck;

View File

@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -280,7 +281,7 @@ class InterestingItemsFilesSetSettings implements Serializable {
if (elem.getTagName().equals(NAME_RULE_TAG)) {
nameCondition = new FilesSet.Rule.FullNameCondition(content);
} else if (elem.getTagName().equals(EXTENSION_RULE_TAG)) {
nameCondition = new FilesSet.Rule.ExtensionCondition(content);
nameCondition = new FilesSet.Rule.ExtensionCondition(Arrays.asList(content.split(",")));
}
}
}

View File

@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataSource;
/*
* A runnable that adds an archive data source as well as data sources contained
@ -195,9 +196,18 @@ class AddArchiveTask implements Runnable {
continue;
}
// if we are here it means the data source was addedd successfully
// if we are here it means the data source was added successfully
success = true;
newDataSources.addAll(internalDataSource.getContent());
// Update the names for all new data sources to be the root archive plus the name of the data source
for (Content c:internalDataSource.getContent()) {
if (c instanceof DataSource) {
DataSource ds = (DataSource) c;
String newName = Paths.get(archivePath).getFileName() + "/" + ds.getName();
ds.setDisplayName(newName);
}
}
// skip all other DSPs for this data source
break;

View File

@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.coreutils.StopWatch;
import org.sleuthkit.autopsy.events.AutopsyEventException;
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingStatus;
@ -666,43 +667,73 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
* @return A result code indicating success, partial success, or failure.
*/
CaseDeletionResult deleteCase(AutoIngestJob job) {
String caseName = job.getManifest().getCaseName();
Path caseDirectoryPath = job.getCaseDirectoryPath();
Path metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension());
StopWatch stopWatch = new StopWatch();
stopWatch.start();
synchronized (jobsLock) {
String caseName = job.getManifest().getCaseName();
Path metadataFilePath = job.getCaseDirectoryPath().resolve(caseName + CaseMetadata.getFileExtension());
stopWatch.stop();
LOGGER.log(Level.INFO, String.format("Used %d s to acquire jobsLock (Java monitor in AutoIngestMonitor class) for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
stopWatch.reset();
stopWatch.start();
try {
CaseMetadata metadata = new CaseMetadata(metadataFilePath);
stopWatch.stop();
LOGGER.log(Level.INFO, String.format("Used %d s to read case metadata for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
stopWatch.reset();
stopWatch.start();
Case.deleteCase(metadata);
} catch (CaseMetadata.CaseMetadataException ex) {
LOGGER.log(Level.SEVERE, String.format("Failed to get case metadata file %s for case %s at %s", metadataFilePath.toString(), caseName, job.getCaseDirectoryPath().toString()), ex);
LOGGER.log(Level.SEVERE, String.format("Failed to read case metadata file %s for case %s at %s", metadataFilePath, caseName, caseDirectoryPath), ex);
stopWatch.stop();
LOGGER.log(Level.INFO, String.format("Used %d s to fail to read case metadata file %s for case %s at %s", stopWatch.getElapsedTimeSecs(), metadataFilePath, caseName, caseDirectoryPath));
return CaseDeletionResult.FAILED;
} catch (CaseActionException ex) {
LOGGER.log(Level.SEVERE, String.format("Failed to physically delete case %s at %s", caseName, job.getCaseDirectoryPath().toString()), ex);
LOGGER.log(Level.SEVERE, String.format("Failed to delete case %s at %s", caseName, caseDirectoryPath), ex);
return CaseDeletionResult.FAILED;
}
// Update the state of completed jobs associated with this case to indicate
// that the case has been deleted
for (AutoIngestJob completedJob : getCompletedJobs()) {
stopWatch.reset();
stopWatch.start();
List<AutoIngestJob> completedJobs = getCompletedJobs();
stopWatch.stop();
LOGGER.log(Level.INFO, String.format("Used %d s to get completed jobs listing for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
stopWatch.reset();
stopWatch.start();
for (AutoIngestJob completedJob : completedJobs) {
if (caseName.equals(completedJob.getManifest().getCaseName())) {
try {
completedJob.setProcessingStatus(DELETED);
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(completedJob);
coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, completedJob.getManifest().getFilePath().toString(), nodeData.toArray());
} catch (CoordinationServiceException | InterruptedException ex) {
LOGGER.log(Level.SEVERE, String.format("Failed to update completed job node data for %s when deleting case %s", completedJob.getManifest().getFilePath().toString(), caseName), ex);
LOGGER.log(Level.SEVERE, String.format("Failed to update completed job node data for %s when deleting case %s at %s", completedJob.getManifest().getFilePath(), caseName, caseDirectoryPath), ex);
stopWatch.stop();
LOGGER.log(Level.INFO, String.format("Used %d s to fail to update job node data for completed jobs for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
return CaseDeletionResult.PARTIALLY_DELETED;
}
}
}
stopWatch.stop();
LOGGER.log(Level.INFO, String.format("Used %d s to update job node data for completed jobs for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
// Remove jobs associated with this case from the completed jobs collection.
jobsSnapshot.completedJobs.removeIf((AutoIngestJob completedJob)
stopWatch.reset();
stopWatch.start();
completedJobs.removeIf((AutoIngestJob completedJob)
-> completedJob.getManifest().getCaseName().equals(caseName));
stopWatch.stop();
LOGGER.log(Level.INFO, String.format("Used %d s to remove completed jobs for case %s at %s from current jobs snapshot", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
// Publish a message to update auto ingest nodes.
stopWatch.reset();
stopWatch.start();
eventPublisher.publishRemotely(new AutoIngestCaseDeletedEvent(caseName, LOCAL_HOST_NAME, AutoIngestManager.getSystemUserNameProperty()));
stopWatch.stop();
LOGGER.log(Level.INFO, String.format("Used %d s to publish job deletion event for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName,caseDirectoryPath));
}
return CaseDeletionResult.FULLY_DELETED;

View File

@ -25,9 +25,7 @@ import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.TreeSet;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
@ -43,6 +41,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class MemoryDSInputPanel extends JPanel implements DocumentListener {
@ -132,26 +131,13 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
* machine time zone to be selected.
*/
private void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
timeZoneComboBox.addItem(item);
List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
for (String timeZone : timeZoneList) {
timeZoneComboBox.addItem(timeZone);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}

View File

@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.imagegallery/2
OpenIDE-Module-Implementation-Version: 4
OpenIDE-Module-Implementation-Version: 5
OpenIDE-Module-Layer: org/sleuthkit/autopsy/imagegallery/layer.xml
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/imagegallery/Bundle.properties

View File

@ -11,4 +11,4 @@ ImageGalleryOptionsPanel.descriptionLabel.text=<html>To minimize its startup tim
ImageGalleryOptionsPanel.furtherDescriptionArea.text=If Image Gallery is disabled, only the fact that an update is needed is recorded. If Image Gallery is enabled after ingest, it will do one bulk update based on the results from ingest. If Image Gallery is disabled, you will be prompted to enable it when attempting to open its window.
ImageGalleryOptionsPanel.unavailableDuringInjestLabel.text=This setting is unavailable during ingest.
ImageGalleryOptionsPanel.groupCategorizationWarningBox.text=Don't show a warning when overwriting categories, by acting on an entire group.
CTL_OpenAction=Open Image/Video
CTL_OpenAction=Open Image/Video

View File

@ -219,8 +219,13 @@ public enum FileTypeUtils {
* type. False if a non image/video mimetype. empty Optional if a
* mimetype could not be detected.
*/
static boolean hasDrawableMIMEType(AbstractFile file) throws FileTypeDetector.FileTypeDetectorInitException {
String mimeType = getFileTypeDetector().getMIMEType(file).toLowerCase();
static boolean hasDrawableMIMEType(AbstractFile file) {
String mimeType = file.getMIMEType();
if (mimeType == null) {
return false;
}
mimeType = mimeType.toLowerCase();
return isDrawableMimeType(mimeType) || (mimeType.equals("audio/x-aiff") && "tiff".equalsIgnoreCase(file.getNameExtension()));
}
@ -234,13 +239,13 @@ public enum FileTypeUtils {
* available, a video extension.
*/
public static boolean hasVideoMIMEType(AbstractFile file) {
try {
String mimeType = getFileTypeDetector().getMIMEType(file).toLowerCase();
return mimeType.startsWith("video/") || videoMimeTypes.contains(mimeType);
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
LOGGER.log(Level.SEVERE, "Error determining MIME type of " + getContentPathSafe(file), ex);
String mimeType = file.getMIMEType();
if (mimeType == null) {
return false;
}
mimeType = mimeType.toLowerCase();
return mimeType.startsWith("video/") || videoMimeTypes.contains(mimeType);
}
/**

View File

@ -67,7 +67,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -232,19 +231,19 @@ public final class ImageGalleryController {
dbTaskQueueSize.addListener(obs -> this.updateRegroupDisabled());
}
/**
* @return Currently displayed group or null if nothing is being displayed
*/
public GroupViewState getViewState() {
return historyManager.getCurrentState();
}
/**
* Get observable property of the current group. The UI currently changes
* based on this property changing, which happens when other actions and
* based on this property changing, which happens when other actions and
* threads call advance().
*
*
* @return Currently displayed group (as a property that can be observed)
*/
public ReadOnlyObjectProperty<GroupViewState> viewStateProperty() {
@ -253,7 +252,8 @@ public final class ImageGalleryController {
/**
* Should the "forward" button on the history be enabled?
* @return
*
* @return
*/
public ReadOnlyBooleanProperty getCanAdvance() {
return historyManager.getCanAdvance();
@ -261,19 +261,19 @@ public final class ImageGalleryController {
/**
* Should the "Back" button on the history be enabled?
* @return
*
* @return
*/
public ReadOnlyBooleanProperty getCanRetreat() {
return historyManager.getCanRetreat();
}
/**
* Display the passed in group. Causes this group to
* get recorded in the history queue and observers of the
* current state will be notified and update their panels/widgets
* appropriately.
*
* @param newState
* Display the passed in group. Causes this group to get recorded in the
* history queue and observers of the current state will be notified and
* update their panels/widgets appropriately.
*
* @param newState
*/
@ThreadConfined(type = ThreadConfined.ThreadType.ANY)
public void advance(GroupViewState newState) {
@ -282,7 +282,8 @@ public final class ImageGalleryController {
/**
* Display the next group in the "forward" history stack
* @return
*
* @return
*/
public GroupViewState advance() {
return historyManager.advance();
@ -290,7 +291,8 @@ public final class ImageGalleryController {
/**
* Display the previous group in the "back" history stack
* @return
*
* @return
*/
public GroupViewState retreat() {
return historyManager.retreat();
@ -433,10 +435,6 @@ public final class ImageGalleryController {
return drawableDB.getFileFromID(fileID);
}
public ReadOnlyDoubleProperty regroupProgress() {
return groupManager.regroupProgress();
}
public HashSetManager getHashSetManager() {
return hashSetManager;
}
@ -696,8 +694,17 @@ public final class ImageGalleryController {
// Cycle through all of the files returned and call processFile on each
//do in transaction
drawableDbTransaction = taskDB.beginTransaction();
caseDbTransaction = tskCase.beginTransaction();
/* We are going to periodically commit the CaseDB transaction
* and sleep so that the user can have Autopsy do other stuff
* while these bulk tasks are ongoing.
*/
int caseDbCounter = 0;
for (final AbstractFile f : files) {
if (caseDbTransaction == null) {
caseDbTransaction = tskCase.beginTransaction();
}
if (isCancelled() || Thread.interrupted()) {
logger.log(Level.WARNING, "Task cancelled or interrupted: not all contents may be transfered to drawable database."); //NON-NLS
taskCompletionStatus = false;
@ -712,6 +719,14 @@ public final class ImageGalleryController {
progressHandle.progress(f.getName(), workDone);
updateProgress(workDone - 1 / (double) files.size());
updateMessage(f.getName());
// Periodically, commit the transaction (which frees the lock) and sleep
// to allow other threads to get some work done in CaseDB
if ((++caseDbCounter % 200) == 0) {
caseDbTransaction.commit();
caseDbTransaction = null;
Thread.sleep(500); // 1/2 second
}
}
progressHandle.finish();
@ -720,13 +735,16 @@ public final class ImageGalleryController {
updateProgress(1.0);
progressHandle.start();
caseDbTransaction.commit();
caseDbTransaction = null;
if (caseDbTransaction != null) {
caseDbTransaction.commit();
caseDbTransaction = null;
}
// pass true so that groupmanager is notified of the changes
taskDB.commitTransaction(drawableDbTransaction, true);
drawableDbTransaction = null;
} catch (TskCoreException ex) {
} catch (TskCoreException | InterruptedException ex) {
progressHandle.progress(Bundle.BulkTask_stopCopy_status());
logger.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS
MessageNotifyUtil.Notify.warn(Bundle.BulkTask_errPopulating_errMsg(), ex.getMessage());
@ -792,20 +810,16 @@ public final class ImageGalleryController {
if (known) {
taskDB.removeFile(f.getId(), tr); //remove known files
} else {
try {
// if mimetype of the file hasn't been ascertained, ingest might not have completed yet.
if (null == f.getMIMEType()) {
// set to false to force the DB to be marked as stale
this.setTaskCompletionStatus(false);
} //supported mimetype => analyzed
else if (FileTypeUtils.hasDrawableMIMEType(f)) {
taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction);
} //unsupported mimtype => analyzed but shouldn't include
else {
taskDB.removeFile(f.getId(), tr);
}
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
throw new TskCoreException("Failed to initialize FileTypeDetector.", ex);
// if mimetype of the file hasn't been ascertained, ingest might not have completed yet.
if (null == f.getMIMEType()) {
// set to false to force the DB to be marked as stale
this.setTaskCompletionStatus(false);
} //supported mimetype => analyzed
else if (FileTypeUtils.hasDrawableMIMEType(f)) {
taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction);
} //unsupported mimtype => analyzed but shouldn't include
else {
taskDB.removeFile(f.getId(), tr);
}
}
}
@ -840,7 +854,7 @@ public final class ImageGalleryController {
@Override
void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDBTransaction) {
taskDB.insertFile(DrawableFile.create(f, false, false), tr, caseDBTransaction);
taskDB.insertBasicFileData(DrawableFile.create(f, false, false), tr, caseDBTransaction);
}
@Override

View File

@ -154,14 +154,14 @@ public class ImageGalleryModule {
IngestManager.getInstance().removeIngestModuleEventListener(this);
return;
}
/* only process individual files in realtime on the node that is
* running the ingest. on a remote node, image files are processed
* enblock when ingest is complete */
if (((AutopsyEvent) evt).getSourceType() != AutopsyEvent.SourceType.LOCAL) {
return;
}
// Bail out if the case is closed
try {
if (controller == null || Case.getCurrentCaseThrows() == null) {
@ -208,8 +208,8 @@ public class ImageGalleryModule {
}
}
else if (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName()) == DATA_ADDED) {
ModuleDataEvent mde = (ModuleDataEvent)evt.getOldValue();
ModuleDataEvent mde = (ModuleDataEvent) evt.getOldValue();
if (mde.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
DrawableDB drawableDB = controller.getDatabase();
if (mde.getArtifacts() != null) {
@ -288,13 +288,13 @@ public class ImageGalleryModule {
break;
case CONTENT_TAG_ADDED:
final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt;
long objId = tagAddedEvent.getAddedTag().getContent().getId();
// update the cache
DrawableDB drawableDB = controller.getDatabase();
drawableDB.addTagCache(objId);
if (con.getDatabase().isInDB(objId)) {
con.getTagsManager().fireTagAddedEvent(tagAddedEvent);
}
@ -336,21 +336,23 @@ public class ImageGalleryModule {
try {
ImageGalleryController con = getController();
con.setStale(true);
if (con.isListeningEnabled() && ImageGalleryTopComponent.isImageGalleryOpen()) {
if (con.isListeningEnabled()) {
SwingUtilities.invokeLater(() -> {
int showAnswer = JOptionPane.showConfirmDialog(ImageGalleryTopComponent.getTopComponent(),
Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_msg(),
Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_title(),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
if (ImageGalleryTopComponent.isImageGalleryOpen()) {
int showAnswer = JOptionPane.showConfirmDialog(ImageGalleryTopComponent.getTopComponent(),
Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_msg(),
Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_title(),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
switch (showAnswer) {
case JOptionPane.YES_OPTION:
con.rebuildDB();
break;
case JOptionPane.NO_OPTION:
case JOptionPane.CANCEL_OPTION:
default:
break; //do nothing
switch (showAnswer) {
case JOptionPane.YES_OPTION:
con.rebuildDB();
break;
case JOptionPane.NO_OPTION:
case JOptionPane.CANCEL_OPTION:
default:
break; //do nothing
}
}
});
}

View File

@ -698,8 +698,8 @@ public final class DrawableDB {
// query to find the group id from attribute/value
return String.format(" SELECT group_id FROM " + GROUPS_TABLENAME
+ " WHERE attribute = \'%s\' AND value = \'%s\' AND data_source_obj_id = %d",
groupKey.getAttribute().attrName.toString(),
groupKey.getValueDisplayName(),
SleuthkitCase.escapeSingleQuotes(groupKey.getAttribute().attrName.toString()),
SleuthkitCase.escapeSingleQuotes(groupKey.getValueDisplayName()),
(groupKey.getAttribute() == DrawableAttribute.PATH) ? groupKey.getDataSourceObjId() : 0);
}
@ -776,8 +776,8 @@ public final class DrawableDB {
// query to find the group id from attribute/value
String innerQuery = String.format("( SELECT group_id FROM " + GROUPS_TABLENAME
+ " WHERE attribute = \'%s\' AND value = \'%s\' and data_source_obj_id = %d )",
groupKey.getAttribute().attrName.toString(),
groupKey.getValueDisplayName(),
SleuthkitCase.escapeSingleQuotes(groupKey.getAttribute().attrName.toString()),
SleuthkitCase.escapeSingleQuotes(groupKey.getValueDisplayName()),
groupKey.getAttribute() == DrawableAttribute.PATH ? groupKey.getDataSourceObjId() : 0);
String insertSQL = String.format(" (group_id, examiner_id, seen) VALUES (%s, %d, %d)", innerQuery, examinerID, seen ? 1 : 0);
@ -828,12 +828,26 @@ public final class DrawableDB {
}
public void insertFile(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, insertFileStmt, caseDbTransaction);
/**
* Insert basic file data (no groups) into the DB during pre-population phase
* @param f
* @param tr
* @param caseDbTransaction
*/
public void insertBasicFileData(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, caseDbTransaction, false);
}
/**
* Update an existing entry (or make a new one) into the DB that includes group information.
* Called when a file has been analyzed or during a bulk rebuild
*
* @param f
* @param tr
* @param caseDbTransaction
*/
public void updateFile(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, updateFileStmt, caseDbTransaction);
insertOrUpdateFile(f, tr, caseDbTransaction, true);
}
@ -964,14 +978,24 @@ public final class DrawableDB {
*
* @param f The file to insert.
* @param tr a transaction to use, must not be null
* @param stmt the statement that does the actual inserting
* @param caseDbTransaction
* @param addGroups True if groups for file should be inserted into db too
*/
private void insertOrUpdateFile(DrawableFile f, @Nonnull DrawableTransaction tr, @Nonnull PreparedStatement stmt, @Nonnull CaseDbTransaction caseDbTransaction) {
private void insertOrUpdateFile(DrawableFile f, @Nonnull DrawableTransaction tr, @Nonnull CaseDbTransaction caseDbTransaction, boolean addGroups) {
PreparedStatement stmt;
if (tr.isClosed()) {
throw new IllegalArgumentException("can't update database with closed transaction");
}
// assume that we are doing an update if we are adding groups - i.e. not pre-populating
if (addGroups) {
stmt = updateFileStmt;
} else {
stmt = insertFileStmt;
}
// get data from caches. Default to true and force the DB lookup if we don't have caches
boolean hasExif = true;
boolean hasHashSet = true;
@ -983,6 +1007,13 @@ public final class DrawableDB {
hasTag = hasTagCache.contains(f.getId());
}
}
// if we are going to just add basic data, then mark flags that we do not have metadata to prevent lookups
if (addGroups == false) {
hasExif = false;
hasHashSet = false;
hasTag = false;
}
dbWriteLock();
try {
@ -1006,51 +1037,55 @@ public final class DrawableDB {
// Update the list of file IDs in memory
addImageFileToList(f.getId());
// Update the hash set tables
if (hasHashSet) {
try {
for (String name : f.getHashSetNames()) {
// update the groups if we are not doing pre-populating
if (addGroups) {
// Update the hash set tables
if (hasHashSet) {
try {
for (String name : f.getHashSetNames()) {
// "insert or ignore into hash_sets (hash_set_name) values (?)"
insertHashSetStmt.setString(1, name);
insertHashSetStmt.executeUpdate();
// "insert or ignore into hash_sets (hash_set_name) values (?)"
insertHashSetStmt.setString(1, name);
insertHashSetStmt.executeUpdate();
//TODO: use nested select to get hash_set_id rather than seperate statement/query
//"select hash_set_id from hash_sets where hash_set_name = ?"
selectHashSetStmt.setString(1, name);
try (ResultSet rs = selectHashSetStmt.executeQuery()) {
while (rs.next()) {
int hashsetID = rs.getInt("hash_set_id"); //NON-NLS
//"insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)";
insertHashHitStmt.setInt(1, hashsetID);
insertHashHitStmt.setLong(2, f.getId());
insertHashHitStmt.executeUpdate();
break;
//TODO: use nested select to get hash_set_id rather than seperate statement/query
//"select hash_set_id from hash_sets where hash_set_name = ?"
selectHashSetStmt.setString(1, name);
try (ResultSet rs = selectHashSetStmt.executeQuery()) {
while (rs.next()) {
int hashsetID = rs.getInt("hash_set_id"); //NON-NLS
//"insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)";
insertHashHitStmt.setInt(1, hashsetID);
insertHashHitStmt.setLong(2, f.getId());
insertHashHitStmt.executeUpdate();
break;
}
}
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "failed to insert/update hash hits for file" + f.getContentPathSafe(), ex); //NON-NLS
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "failed to insert/update hash hits for file" + f.getContentPathSafe(), ex); //NON-NLS
}
}
//and update all groups this file is in
for (DrawableAttribute<?> attr : DrawableAttribute.getGroupableAttrs()) {
// skip attributes that we do not have data for
if ((attr == DrawableAttribute.TAGS) && (hasTag == false)) {
continue;
}
else if ((attr == DrawableAttribute.MAKE || attr == DrawableAttribute.MODEL) && (hasExif == false)) {
continue;
}
Collection<? extends Comparable<?>> vals = attr.getValue(f);
for (Comparable<?> val : vals) {
if (null != val) {
if (attr == DrawableAttribute.PATH) {
insertGroup(f.getAbstractFile().getDataSource().getId(), val.toString(), attr, caseDbTransaction);
}
else {
insertGroup(val.toString(), attr, caseDbTransaction);
//and update all groups this file is in
for (DrawableAttribute<?> attr : DrawableAttribute.getGroupableAttrs()) {
// skip attributes that we do not have data for
if ((attr == DrawableAttribute.TAGS) && (hasTag == false)) {
continue;
}
else if ((attr == DrawableAttribute.MAKE || attr == DrawableAttribute.MODEL) && (hasExif == false)) {
continue;
}
Collection<? extends Comparable<?>> vals = attr.getValue(f);
for (Comparable<?> val : vals) {
if ((null != val) && (val.toString().isEmpty() == false)) {
if (attr == DrawableAttribute.PATH) {
insertGroup(f.getAbstractFile().getDataSource().getId(), val.toString(), attr, caseDbTransaction);
}
else {
insertGroup(val.toString(), attr, caseDbTransaction);
}
}
}
}
@ -1408,7 +1443,7 @@ public final class DrawableDB {
try {
String insertSQL = String.format(" (data_source_obj_id, value, attribute) VALUES (%d, \'%s\', \'%s\')",
ds_obj_id, value, groupBy.attrName.toString());
ds_obj_id, SleuthkitCase.escapeSingleQuotes(value), SleuthkitCase.escapeSingleQuotes(groupBy.attrName.toString()));
if (DbType.POSTGRESQL == tskCase.getDatabaseType()) {
insertSQL += " ON CONFLICT DO NOTHING";

View File

@ -68,13 +68,6 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
DrawableGroup(GroupKey<?> groupKey, Set<Long> filesInGroup, boolean seen) {
this.groupKey = groupKey;
this.fileIDs.setAll(filesInGroup);
fileIDs.addListener((ListChangeListener.Change<? extends Long> listchange) -> {
boolean seenChanged = false;
while (false == seenChanged && listchange.next()) {
seenChanged |= listchange.wasAdded();
}
invalidateProperties(seenChanged);
});
this.seen.set(seen);
}
@ -183,15 +176,21 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
if (fileIDs.contains(f) == false) {
fileIDs.add(f);
}
// invalidate no matter what because the file could have new hash hits, etc.
invalidateProperties(true);
}
synchronized void setFiles(Set<? extends Long> newFileIds) {
fileIDs.removeIf(fileID -> newFileIds.contains(fileID) == false);
invalidateProperties(false);
newFileIds.stream().forEach(this::addFile);
}
synchronized void removeFile(Long f) {
fileIDs.removeAll(f);
if (fileIDs.contains(f)) {
fileIDs.removeAll(f);
invalidateProperties(false);
}
}
private void invalidateProperties(boolean seenChanged) {

View File

@ -50,6 +50,7 @@ import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
@ -266,14 +267,23 @@ public class GroupManager {
try {
Examiner examiner = controller.getSleuthKitCase().getCurrentExaminer();
getDrawableDB().markGroupSeen(group.getGroupKey(), seen, examiner.getId());
group.setSeen(seen);
updateUnSeenGroups(group);
// only update and reshuffle if its new results
if (group.isSeen() != seen) {
group.setSeen(seen);
updateUnSeenGroups(group);
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error marking group as seen", ex); //NON-NLS
}
});
}
/**
* Update unseenGroups list accordingly based on the current status of
* 'group'. Removes it if it is seen or adds it if it is unseen.
*
* @param group
*/
synchronized private void updateUnSeenGroups(DrawableGroup group) {
if (group.isSeen()) {
unSeenGroups.removeAll(group);
@ -496,6 +506,10 @@ public class GroupManager {
return regrouper.progressProperty();
}
public ReadOnlyStringProperty regroupMessage() {
return regrouper.messageProperty();
}
@Subscribe
synchronized public void handleTagAdded(ContentTagAddedEvent evt) {
GroupKey<?> newGroupKey = null;
@ -530,15 +544,18 @@ public class GroupManager {
// NOTE: We assume that it has already been determined that GroupKey can be displayed based on Data Source filters
if (group == null) {
//if there wasn't already a group check if there should be one now
// path group, for example, only gets created when all files are analyzed
//if there wasn't already a DrawableGroup, then check if this group is now
// in an appropriate state to get one made.
// Path group, for example, only gets a DrawableGroup created when all files are analyzed
group = popuplateIfAnalyzed(groupKey, null);
} else {
//if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it.
group.addFile(fileID);
}
// reset the seen status for the group
markGroupSeen(group, false);
if (group != null) {
markGroupSeen(group, false);
}
}
@Subscribe
@ -607,6 +624,8 @@ public class GroupManager {
* If the group is analyzed (or other criteria based on grouping) and should
* be shown to the user, then add it to the appropriate data structures so
* that it can be viewed.
*
* @returns null if Group is not ready to be viewed
*/
synchronized private DrawableGroup popuplateIfAnalyzed(GroupKey<?> groupKey, ReGroupTask<?> task) {
/*
@ -716,12 +735,7 @@ public class GroupManager {
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@NbBundle.Messages({"# {0} - groupBy attribute Name",
"# {1} - sortBy name",
"# {2} - sort Order",
"ReGroupTask.displayTitle=regrouping files by {0} sorted by {1} in {2} order",
"# {0} - groupBy attribute Name",
"# {1} - atribute value",
"ReGroupTask.progressUpdate=regrouping files by {0} : {1}"})
"ReGroupTask.displayTitle=regrouping by {0}: " })
class ReGroupTask<AttrValType extends Comparable<AttrValType>> extends LoggedTask<Void> {
private final DataSource dataSource;
@ -729,16 +743,14 @@ public class GroupManager {
private final GroupSortBy sortBy;
private final SortOrder sortOrder;
private final ProgressHandle groupProgress;
ReGroupTask(DataSource dataSource, DrawableAttribute<AttrValType> groupBy, GroupSortBy sortBy, SortOrder sortOrder) {
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), true);
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString() ), true);
this.dataSource = dataSource;
this.groupBy = groupBy;
this.sortBy = sortBy;
this.sortOrder = sortOrder;
groupProgress = ProgressHandle.createHandle(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), this);
updateTitle(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString() ));
}
@Override
@ -747,7 +759,8 @@ public class GroupManager {
if (isCancelled()) {
return null;
}
groupProgress.start();
updateProgress(-1, 1);
analyzedGroups.clear();
unSeenGroups.clear();
@ -755,7 +768,7 @@ public class GroupManager {
// Get the list of group keys
Multimap<DataSource, AttrValType> valsByDataSource = findValuesForAttribute();
groupProgress.switchToDeterminate(valsByDataSource.entries().size());
updateProgress(0, valsByDataSource.entries().size());
int p = 0;
// For each key value, partially create the group and add it to the list.
for (final Map.Entry<DataSource, AttrValType> valForDataSource : valsByDataSource.entries()) {
@ -763,9 +776,8 @@ public class GroupManager {
return null;
}
p++;
updateMessage(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), valForDataSource.getValue()));
updateMessage(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString()) + valForDataSource.getValue());
updateProgress(p, valsByDataSource.size());
groupProgress.progress(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), valForDataSource), p);
popuplateIfAnalyzed(new GroupKey<>(groupBy, valForDataSource.getValue(), valForDataSource.getKey()), this);
}
@ -794,8 +806,8 @@ public class GroupManager {
}
}
} finally {
groupProgress.finish();
updateProgress(1, 1);
updateMessage("");
}
return null;
}
@ -813,12 +825,9 @@ public class GroupManager {
}
/**
* find the distinct values for the given column (DrawableAttribute)
*
* Find the distinct values for the given column (DrawableAttribute).
* These values represent the groups of files.
*
* @param groupBy
*
* @return map of data source (or null if group by attribute ignores
* data sources) to list of unique group values
*/

View File

@ -10,12 +10,21 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<fx:root id="AnchorPane" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" type="javafx.scene.layout.AnchorPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<fx:root id="AnchorPane" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" type="javafx.scene.layout.AnchorPane" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
<children>
<BorderPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<right>
<HBox alignment="CENTER_RIGHT" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" BorderPane.alignment="CENTER_RIGHT">
<children>
<Label fx:id="staleLabel" text="Some data may be out of date. Enable listening to ingest to update.">
<graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/information.png" />
</image>
</ImageView>
</graphic>
</Label>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" HBox.hgrow="NEVER">
<children>
<ProgressBar id="progBar" fx:id="fileTaskProgresBar" focusTraversable="false" maxHeight="-1.0" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-1.0" prefHeight="24.0" prefWidth="-1.0" progress="0.0" visible="true" />
@ -31,37 +40,27 @@
<Insets />
</HBox.margin>
</StackPane>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" HBox.hgrow="NEVER">
<children>
<ProgressBar fx:id="bgTaskProgressBar" maxHeight="-1.0" maxWidth="-1.0" minHeight="-Infinity" minWidth="-1.0" prefHeight="24.0" prefWidth="-1.0" progress="0.0" StackPane.alignment="CENTER" />
<Label fx:id="bgTaskLabel" alignment="CENTER" cache="false" contentDisplay="CENTER" disable="false" focusTraversable="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" text="" StackPane.alignment="CENTER">
<StackPane.margin>
<Insets left="3.0" right="3.0" />
</StackPane.margin>
<padding>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</padding></Label>
</children>
<HBox.margin>
<Insets right="5.0" />
</HBox.margin>
</StackPane>
</children>
<BorderPane.margin>
<Insets left="10.0" />
</BorderPane.margin>
</HBox>
</right>
<left><Label fx:id="staleLabel" text="Some data may be out of date. Enable listening to ingest to update." BorderPane.alignment="CENTER">
<graphic><ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/information.png" />
</image></ImageView>
</graphic>
<BorderPane.margin>
<Insets bottom="5.0" left="5.0" right="10.0" top="5.0" />
</BorderPane.margin></Label>
</left>
<left>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" BorderPane.alignment="CENTER">
<children>
<ProgressBar fx:id="regroupProgressBar" maxHeight="-1.0" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-1.0" prefHeight="24.0" prefWidth="500.0" progress="0.0" StackPane.alignment="CENTER_LEFT" />
<Label fx:id="regroupLabel" cache="false" contentDisplay="CENTER" disable="false" focusTraversable="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="500.0" text="" textOverrun="CENTER_ELLIPSIS" StackPane.alignment="CENTER_LEFT">
<StackPane.margin>
<Insets left="3.0" right="3.0" />
</StackPane.margin>
<padding>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</padding>
</Label>
</children>
</StackPane>
</left>
</BorderPane>
</children>
</fx:root>

View File

@ -28,28 +28,26 @@ import javafx.scene.control.Tooltip;
import javafx.scene.layout.AnchorPane;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager;
/**
*
*/
public class StatusBar extends AnchorPane {
private final ImageGalleryController controller;
@FXML
private ProgressBar fileTaskProgresBar;
@FXML
private Label fileUpdateTaskLabel;
@FXML
private Label bgTaskLabel;
private Label regroupLabel;
@FXML
private Label staleLabel;
@FXML
private ProgressBar bgTaskProgressBar;
private ProgressBar regroupProgressBar;
private final ImageGalleryController controller;
private final GroupManager groupManager;
@FXML
@NbBundle.Messages({"StatusBar.fileUpdateTaskLabel.text= File Update Tasks",
@ -58,23 +56,25 @@ public class StatusBar extends AnchorPane {
void initialize() {
assert fileTaskProgresBar != null : "fx:id=\"fileTaskProgresBar\" was not injected: check your FXML file 'StatusBar.fxml'.";
assert fileUpdateTaskLabel != null : "fx:id=\"fileUpdateTaskLabel\" was not injected: check your FXML file 'StatusBar.fxml'.";
assert bgTaskLabel != null : "fx:id=\"bgTaskLabel\" was not injected: check your FXML file 'StatusBar.fxml'.";
assert bgTaskProgressBar != null : "fx:id=\"bgTaskProgressBar\" was not injected: check your FXML file 'StatusBar.fxml'.";
assert regroupLabel != null : "fx:id=\"regroupLabel\" was not injected: check your FXML file 'StatusBar.fxml'.";
assert regroupProgressBar != null : "fx:id=\"regroupProgressBar\" was not injected: check your FXML file 'StatusBar.fxml'.";
fileUpdateTaskLabel.textProperty().bind(controller.getDBTasksQueueSizeProperty().asString().concat(Bundle.StatusBar_fileUpdateTaskLabel_text()));
fileTaskProgresBar.progressProperty().bind(controller.getDBTasksQueueSizeProperty().negate());
controller.regroupProgress().addListener((ov, oldSize, newSize) -> {
groupManager.regroupProgress().addListener((ov, oldSize, newSize) -> {
Platform.runLater(() -> {
if (controller.regroupProgress().lessThan(1.0).get()) {
if (groupManager.regroupProgress().lessThan(1.0).get()) {
// Regrouping in progress
bgTaskProgressBar.progressProperty().setValue(-1.0);
bgTaskLabel.setText(Bundle.StatusBar_bgTaskLabel_text());
regroupProgressBar.progressProperty().setValue(groupManager.regroupProgress().doubleValue());
regroupLabel.setText(groupManager.regroupMessage().get());
} else {
// Clear the progress bar
bgTaskProgressBar.progressProperty().setValue(0.0);
bgTaskLabel.setText("");
regroupProgressBar.progressProperty().setValue(0.0);
regroupLabel.setText("");
}
regroupLabel.setTooltip(new Tooltip(regroupLabel.getText()));
});
});
@ -84,6 +84,7 @@ public class StatusBar extends AnchorPane {
public StatusBar(ImageGalleryController controller) {
this.controller = controller;
this.groupManager = controller.getGroupManager();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("StatusBar.fxml")); //NON-NLS
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
@ -93,6 +94,5 @@ public class StatusBar extends AnchorPane {
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@ -1,3 +1,9 @@
---------------- VERSION 4.9.1 --------------
Bug Fixes:
- Fixed possible ingest deadlock from Image Gallery database inserts.
- Image Gallery does not need lock on Case DB during pre-population, which makes UI more responsive.
- Other misc Image Gallery fixes.
---------------- VERSION 4.9.0 --------------
New Features:

View File

@ -73,9 +73,7 @@
</run-dependency>
</dependency>
</module-dependencies>
<public-packages>
<package>org.sleuthkit.autopsy.recentactivity</package>
</public-packages>
<public-packages/>
<class-path-extension>
<runtime-relative-path>ext/gson-2.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/gson-2.1.jar</binary-origin>

View File

@ -37,6 +37,7 @@ import java.util.*;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile;
@ -309,7 +310,7 @@ final class Chrome extends Extract {
} else {
date = Long.valueOf(0);
}
String domain = Util.extractDomain(url);
String domain = NetworkUtils.extractDomain(url);
try {
Collection<BlackboardAttribute> bbattributes = Arrays.asList(
new BlackboardAttribute(
@ -520,6 +521,7 @@ final class Chrome extends Extract {
try {
BlackboardArtifact bbart = downloadFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD);
bbart.addAttributes(bbattributes);
bbartifacts.add(bbart);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error while trying to insert Chrome download artifact.", ex); //NON-NLS
@ -589,6 +591,7 @@ final class Chrome extends Extract {
List<HashMap<String, Object>> tempList = this.dbConnect(temps, LOGIN_QUERY);
logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2}artifacts identified.", new Object[]{getModuleName(), temps, tempList.size()}); //NON-NLS
for (HashMap<String, Object> result : tempList) {
Collection<BlackboardAttribute> bbattributes = Arrays.asList(
new BlackboardAttribute(
TSK_URL, PARENT_MODULE_NAME,
@ -618,6 +621,7 @@ final class Chrome extends Extract {
try {
BlackboardArtifact bbart = signonFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY);
bbart.addAttributes(bbattributes);
bbartifacts.add(bbart);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error while trying to insert Chrome login artifact.", ex); //NON-NLS

View File

@ -159,6 +159,7 @@ class ExtractIE extends Extract {
try {
BlackboardArtifact bbart = fav.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
bbart.addAttributes(bbattributes);
bbartifacts.add(bbart);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error while trying to create Internet Explorer bookmark artifact.", ex); //NON-NLS
@ -596,6 +597,7 @@ class ExtractIE extends Extract {
}
/**
*
* Determine if the URL should be ignored.
*
* @param url The URL to test.

View File

@ -22,14 +22,12 @@
*/
package org.sleuthkit.autopsy.recentactivity;
import com.google.common.collect.Lists;
import static com.google.common.collect.Lists.newArrayList;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@ -152,7 +150,7 @@ final class FirefoxExtractor extends Extract {
}
List<HashMap<String, Object>> tempList = this.dbConnect(temps, HISTORY_QUERY);
logger.log(Level.INFO, "{0} - Now getting history from {1} with {2} artifacts identified.", new Object[]{getModuleName(), temps, tempList.size()}); //NON-NLS
for (HashMap<String, Object> result : tempList) {
for (HashMap<String, Object> result : tempList) {
String url = Objects.toString(result.get("url"), "");
Collection<BlackboardAttribute> bbattributes = newArrayList(
new BlackboardAttribute(
@ -169,7 +167,7 @@ final class FirefoxExtractor extends Extract {
Objects.toString(result.get("title"), "")), //NON-NLS
new BlackboardAttribute(
TSK_PROG_NAME, PARENT_MODULE_NAME,
getModuleName()));
getModuleName()));
if (isIgnoredUrl(url) == false) {
bbattributes.add(new BlackboardAttribute(
@ -249,7 +247,7 @@ final class FirefoxExtractor extends Extract {
}
List<HashMap<String, Object>> tempList = this.dbConnect(temps, BOOKMARK_QUERY);
logger.log(Level.INFO, "{0} - Now getting bookmarks from {1} with {2} artifacts identified.", new Object[]{getModuleName(), temps, tempList.size()}); //NON-NLS
for (HashMap<String, Object> result : tempList) {
for (HashMap<String, Object> result : tempList) {
String url = Objects.toString(result.get("url"), "");
Collection<BlackboardAttribute> bbattributes = newArrayList(
@ -266,7 +264,7 @@ final class FirefoxExtractor extends Extract {
if (isIgnoredUrl(url) == false) {
bbattributes.add(new BlackboardAttribute(
TSK_DOMAIN, PARENT_MODULE_NAME,
Util.extractDomain(url)));
Util.extractDomain(url)));
}
Long createdTime = Long.valueOf(result.get("dateAdded").toString());
if (createdTime > 0) { //NON-NLS
@ -351,7 +349,7 @@ final class FirefoxExtractor extends Extract {
List<HashMap<String, Object>> tempList = this.dbConnect(temps, query);
logger.log(Level.INFO, "{0} - Now getting cookies from {1} with {2} artifacts identified.", new Object[]{getModuleName(), temps, tempList.size()}); //NON-NLS
for (HashMap<String, Object> result : tempList) {
for (HashMap<String, Object> result : tempList) {
String host = Objects.toString(result.get("host"), "");
Collection<BlackboardAttribute> bbattributes = newArrayList(
@ -374,7 +372,7 @@ final class FirefoxExtractor extends Extract {
if (isIgnoredUrl(host) == false) {
bbattributes.add(new BlackboardAttribute(
TSK_DOMAIN, PARENT_MODULE_NAME,
Util.extractDomain(host.replaceFirst("^\\.+(?!$)", ""))));//NON-NLS
Util.extractDomain(host.replaceFirst("^\\.+(?!$)", ""))));//NON-NLS
}
if (checkColumn) {
bbattributes.add(new BlackboardAttribute(
@ -491,10 +489,9 @@ final class FirefoxExtractor extends Extract {
logger.log(Level.SEVERE, "Error decoding Firefox download URL in " + temps, ex); //NON-NLS
errors++;
}
try {
try {
BlackboardArtifact bbart = downloadsFile.newArtifact(TSK_WEB_DOWNLOAD);
bbart.addAttributes(bbattributes);
bbart.addAttributes(bbattributes);
bbartifacts.add(bbart);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error while trying to create Firefox download artifact.", ex); //NON-NLS
@ -607,10 +604,10 @@ final class FirefoxExtractor extends Extract {
bbattributes.add(new BlackboardAttribute(
TSK_PATH_ID, PARENT_MODULE_NAME,
pathID));
}
}
} catch (UnsupportedEncodingException ex) {
logger.log(Level.SEVERE, "Error decoding Firefox download URL in " + temps, ex); //NON-NLS
errors++;
errors++;
}
try {
@ -642,10 +639,11 @@ final class FirefoxExtractor extends Extract {
}
/**
* Determine if the URL should be ignored.
*
* @param url The URL to test.
*
*s
* @return True if the URL should be ignored; otherwise false.
*/
private boolean isIgnoredUrl(String url) {
@ -653,6 +651,6 @@ final class FirefoxExtractor extends Extract {
* Ignore blank URLS and URLs that begin with the matched text.
*/
return StringUtils.isBlank(url)
|| url.toLowerCase().startsWith(PLACE_URL_PREFIX);
|| url.toLowerCase().startsWith(PLACE_URL_PREFIX);
}
}

View File

@ -50,11 +50,11 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
*
* @author Alex
*
*/
class Util {
private static Logger logger = Logger.getLogger(Util.class.getName());
private static final Logger logger = Logger.getLogger(Util.class.getName());
private Util() {
}
@ -83,8 +83,10 @@ class Util {
}
/**
//JIRA-2384: There is no utility in apache or guave to do this for us?
* //JIRA-2384: There is no utility in apache or guave to do this for us?
*
* @param url
*
* @return empty string if no domain could be found
*/
private static String getBaseDomain(String url) {
@ -110,8 +112,7 @@ class Util {
hostB.append(".");
}
}
String base = hostB.toString();
// verify there are no special characters in there
if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) {
@ -121,8 +122,9 @@ class Util {
}
/**
*
*
* @param value
*
* @return empty string if no domain name was found
*/
public static String extractDomain(String value) {
@ -156,18 +158,8 @@ class Util {
}
public static String getFileName(String value) {
String filename = "";
String filematch = "^([a-zA-Z]\\:)(\\\\[^\\\\/:*?<>\"|]*(?<!\\[ \\]))*(\\.[a-zA-Z]{2,6})$"; //NON-NLS
Pattern p = Pattern.compile(filematch, Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.COMMENTS);
Matcher m = p.matcher(value);
if (m.find()) {
filename = m.group(1);
}
int lastPos = value.lastIndexOf('\\');
filename = (lastPos < 0) ? value : value.substring(lastPos + 1);
return filename.toString();
return (lastPos < 0) ? value : value.substring(lastPos + 1);
}
public static String getPath(String txt) {

View File

@ -1,3 +1,3 @@
<project name="TSK_VERSION">
<property name="TSK_VERSION" value="4.6.3"/>
<property name="TSK_VERSION" value="4.6.4"/>
</project>

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 4.9.0
PROJECT_NUMBER = 4.9.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 4.9.0
PROJECT_NUMBER = 4.9.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears a the top of each page and should give viewer a

View File

@ -4,10 +4,10 @@ app.title=Autopsy
### lowercase version of above
app.name=${branding.token}
### if left unset, version will default to today's date
app.version=4.9.0
app.version=4.9.1
### build.type must be one of: DEVELOPMENT, RELEASE
#build.type=RELEASE
build.type=DEVELOPMENT
build.type=RELEASE
#build.type=DEVELOPMENT
project.org.netbeans.progress=org-netbeans-api-progress
project.org.sleuthkit.autopsy.experimental=Experimental

268
release/update_autopsy_version.pl Executable file
View File

@ -0,0 +1,268 @@
#!/usr/bin/perl
# Updates various Autopsy version numbers
use strict;
use File::Copy;
# global variables
my $VER;
my $TESTING = 0;
print "TESTING MODE (no commits)\n" if ($TESTING);
sub main {
# Get the Autopsy version argument
if (scalar (@ARGV) != 1) {
print stderr "Missing release version argument (i.e. 4.9.0)\n";
exit;
}
$VER = $ARGV[0];
die "Invalid version number: $VER (1.2.3 or 1.2.3b1 expected)" unless ($VER =~ /^\d+\.\d+\.\d+(b\d+)?$/);
my $AUT_RELNAME = "autopsy-${VER}";
# Verify the tag doesn't already exist
exec_pipe(*OUT, "git tag | grep \"${AUT_RELNAME}\$\"");
my $foo = read_pipe_line(*OUT);
if ($foo ne "") {
print "Tag ${AUT_RELNAME} already exists\n";
print "Remove with 'git tag -d ${AUT_RELNAME}'\n";
die "stopping";
}
close(OUT);
# Assume we running out of 'release' folder
chdir ".." or die "Error changing directories to root";
# verify_precheckin();
# Update the version info in that tag
update_project_properties();
update_doxygen_dev();
update_doxygen_user();
print "Files updated. You need to commit and push them\n";
}
######################################################
# Utility functions
# Function to execute a command and send output to pipe
# returns handle
# exec_pipe(HANDLE, CMD);
sub exec_pipe {
my $handle = shift(@_);
my $cmd = shift(@_);
die "Can't open pipe for exec_pipe"
unless defined(my $pid = open($handle, '-|'));
if ($pid) {
return $handle;
}
else {
$| = 1;
exec("$cmd") or die "Can't exec program: $!";
}
}
# Read a line of text from an open exec_pipe handle
sub read_pipe_line {
my $handle = shift(@_);
my $out;
for (my $i = 0; $i < 100; $i++) {
$out = <$handle>;
return $out if (defined $out);
}
return $out;
}
# Prompt user for argument and return response
sub prompt_user {
my $q = shift(@_);
print "$q: ";
$| = 1;
$_ = <STDIN>;
chomp;
return $_;
}
#############################################
# File update methods
# Verify that all files in the current source directory
# are checked in. dies if any are modified.
sub verify_precheckin {
#system ("git pull");
print "Verifying everything is checked in\n";
exec_pipe(*OUT, "git status -s | grep \"^ M\"");
my $foo = read_pipe_line(*OUT);
if ($foo ne "") {
print "Files not checked in\n";
while ($foo ne "") {
print "$foo";
$foo = read_pipe_line(*OUT);
}
die "stopping" unless ($TESTING);
}
close(OUT);
print "Verifying everything is pushed\n";
exec_pipe(*OUT, "git status -sb | grep \"^##\" | grep \"ahead \"");
my $foo = read_pipe_line(*OUT);
if ($foo ne "") {
print "$foo";
print "Files not pushed to remote\n";
die "stopping" unless ($TESTING);
}
close(OUT);
}
# update the version in nbproject/project.properties
sub update_project_properties {
my $orig = "project.properties";
my $temp = "${orig}-bak";
print "Updating the version in ${orig}\n";
chdir "nbproject" or die "cannot change into nbproject directory";
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
my $found = 0;
while (<CONF_IN>) {
if (/^app\.version=/) {
print CONF_OUT "app.version=$VER\n";
$found++;
}
else {
print CONF_OUT $_;
}
}
close (CONF_IN);
close (CONF_OUT);
if ($found != 1) {
die "$found (instead of 1) occurrences of app.version found in ${orig}";
}
unlink ($orig) or die "Error deleting ${orig}";
rename ($temp, $orig) or die "Error renaming tmp $orig file";
system("git add ${orig}") unless ($TESTING);
chdir ".." or die "Error changing directories back to root";
}
# update the dev docs
sub update_doxygen_dev {
my $orig = "Doxyfile";
my $temp = "${orig}-bak";
print "Updating the version in ${orig} (Dev)\n";
chdir "docs/doxygen" or die "cannot change into docs/doxygen directory";
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
my $found = 0;
while (<CONF_IN>) {
if (/^PROJECT_NUMBER/) {
print CONF_OUT "PROJECT_NUMBER = ${VER}\n";
$found++;
}
elsif (/^HTML_OUTPUT/) {
print CONF_OUT "HTML_OUTPUT = api-docs/${VER}/\n";
$found++;
}
else {
print CONF_OUT $_;
}
}
close (CONF_IN);
close (CONF_OUT);
if ($found != 2) {
die "$found (instead of 2) occurrences of version found in (DEV) ${orig}";
}
unlink ($orig) or die "Error deleting ${orig}";
rename ($temp, $orig) or die "Error renaming tmp $orig file";
system("git add ${orig}") unless ($TESTING);
chdir "../.." or die "Error changing directories back to root";
}
# update the user docs
sub update_doxygen_user {
my $orig = "Doxyfile";
my $temp = "${orig}-bak";
print "Updating the version in ${orig} (User)\n";
chdir "docs/doxygen-user" or die "cannot change into docs/doxygen-user directory";
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
my $found = 0;
while (<CONF_IN>) {
if (/^PROJECT_NUMBER/) {
print CONF_OUT "PROJECT_NUMBER = ${VER}\n";
$found++;
}
elsif (/^HTML_OUTPUT/) {
print CONF_OUT "HTML_OUTPUT = ${VER}\n";
$found++;
}
else {
print CONF_OUT $_;
}
}
close (CONF_IN);
close (CONF_OUT);
if ($found != 2) {
die "$found (instead of 2) occurrences of version found in (USER) ${orig}";
}
unlink ($orig) or die "Error deleting ${orig}";
rename ($temp, $orig) or die "Error renaming tmp $orig file";
system("git add ${orig}") unless ($TESTING);
chdir "../.." or die "Error changing directories back to root";
}
main();

View File

@ -0,0 +1,199 @@
#!/usr/bin/perl
# Updates various TSK version numbers
# use this when the version of TSK that Autopsy depends on changes
use strict;
use File::Copy;
# global variables
my $VER;
my $TESTING = 0;
print "TESTING MODE (no commits)\n" if ($TESTING);
sub main {
# Get the TSK version argument
if (scalar (@ARGV) != 1) {
print stderr "Missing release version argument (i.e. 4.9.0)\n";
exit;
}
$VER = $ARGV[0];
die "Invalid version number: $VER (1.2.3 or 1.2.3b1 expected)" unless ($VER =~ /^\d+\.\d+\.\d+(b\d+)?$/);
# Assume we running out of 'release' folder
chdir ".." or die "Error changing directories to root";
# Update the version info in that tag
update_tsk_version();
update_core_project_properties();
update_core_project_xml();
print "Files updated. You need to commit and push them\n";
}
######################################################
# Utility functions
# Function to execute a command and send output to pipe
# returns handle
# exec_pipe(HANDLE, CMD);
sub exec_pipe {
my $handle = shift(@_);
my $cmd = shift(@_);
die "Can't open pipe for exec_pipe"
unless defined(my $pid = open($handle, '-|'));
if ($pid) {
return $handle;
}
else {
$| = 1;
exec("$cmd") or die "Can't exec program: $!";
}
}
# Read a line of text from an open exec_pipe handle
sub read_pipe_line {
my $handle = shift(@_);
my $out;
for (my $i = 0; $i < 100; $i++) {
$out = <$handle>;
return $out if (defined $out);
}
return $out;
}
#############################################
# File update methods
# update the tskversion.xml
sub update_tsk_version {
my $orig = "TSKVersion.xml";
my $temp = "${orig}-bak";
print "Updating the version in ${orig}\n";
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
my $found = 0;
while (<CONF_IN>) {
if (/name="TSK_VERSION" value=/) {
print CONF_OUT " <property name=\"TSK_VERSION\" value=\"${VER}\"/>\n";
$found++;
}
else {
print CONF_OUT $_;
}
}
close (CONF_IN);
close (CONF_OUT);
if ($found != 1) {
die "$found (instead of 1) occurrences of app.version found in ${orig}";
}
unlink ($orig) or die "Error deleting ${orig}";
rename ($temp, $orig) or die "Error renaming tmp $orig file";
system("git add ${orig}") unless ($TESTING);
}
sub update_core_project_properties {
my $orig = "project.properties";
my $temp = "${orig}-bak";
print "Updating the version in ${orig}\n";
chdir "Core/nbproject" or die "cannot change into Core/nbproject directory";
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
my $found = 0;
while (<CONF_IN>) {
if (/^file\.reference\.sleuthkit\-postgresql-/) {
print CONF_OUT "file.reference.sleuthkit-postgresql-${VER}.jar=release/modules/ext/sleuthkit-postgresql-${VER}.jar\n";
$found++;
}
else {
print CONF_OUT $_;
}
}
close (CONF_IN);
close (CONF_OUT);
if ($found != 1) {
die "$found (instead of 1) occurrences of version found in ${orig}";
}
unlink ($orig) or die "Error deleting ${orig}";
rename ($temp, $orig) or die "Error renaming tmp $orig file";
system("git add ${orig}") unless ($TESTING);
chdir "../.." or die "Error changing directories back to root";
}
sub update_core_project_xml {
my $orig = "project.xml";
my $temp = "${orig}-bak";
print "Updating the version in ${orig}\n";
chdir "Core/nbproject" or die "cannot change into Core/nbproject directory";
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
my $found = 0;
while (<CONF_IN>) {
if (/<runtime-relative-path>ext\/sleuthkit-postgresql/) {
print CONF_OUT " <runtime-relative-path>ext/sleuthkit-postgresql-${VER}.jar</runtime-relative-path>\n";
$found++;
}
elsif (/<binary-origin>release\/modules\/ext\/sleuthkit-postgresql/) {
print CONF_OUT " <binary-origin>release/modules/ext/sleuthkit-postgresql-${VER}.jar</binary-origin>\n";
$found++;
}
else {
print CONF_OUT $_;
}
}
close (CONF_IN);
close (CONF_OUT);
if ($found != 2) {
die "$found (instead of 2) occurrences of version found in ${orig}";
}
unlink ($orig) or die "Error deleting ${orig}";
rename ($temp, $orig) or die "Error renaming tmp $orig file";
system("git add ${orig}") unless ($TESTING);
chdir "../.." or die "Error changing directories back to root";
}
main();