19 package org.sleuthkit.autopsy.casemodule;
22 import java.awt.Frame;
23 import java.awt.event.ActionEvent;
24 import java.awt.event.ActionListener;
25 import java.beans.PropertyChangeListener;
26 import java.beans.PropertyChangeSupport;
28 import java.io.IOException;
29 import java.nio.file.InvalidPathException;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.sql.Connection;
33 import java.sql.DriverManager;
34 import java.sql.SQLException;
35 import java.sql.Statement;
36 import java.text.ParseException;
37 import java.text.SimpleDateFormat;
38 import java.util.Collection;
39 import java.util.Date;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.List;
45 import java.util.TimeZone;
46 import java.util.UUID;
47 import java.util.concurrent.CancellationException;
48 import java.util.concurrent.ExecutionException;
49 import java.util.concurrent.ExecutorService;
50 import java.util.concurrent.Executors;
51 import java.util.concurrent.Future;
52 import java.util.concurrent.ThreadFactory;
53 import java.util.concurrent.TimeUnit;
54 import java.util.logging.Level;
55 import java.util.stream.Collectors;
56 import java.util.stream.Stream;
57 import javax.annotation.concurrent.GuardedBy;
58 import javax.annotation.concurrent.ThreadSafe;
59 import javax.swing.JOptionPane;
60 import javax.swing.SwingUtilities;
61 import org.openide.util.Lookup;
62 import org.openide.util.NbBundle;
63 import org.openide.util.NbBundle.Messages;
64 import org.openide.util.actions.CallableSystemAction;
65 import org.openide.windows.WindowManager;
121 import org.
sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
161 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
164 mainFrame = WindowManager.getDefault().getMainWindow();
187 if (typeName != null) {
189 if (typeName.equalsIgnoreCase(c.toString())) {
213 "Case_caseType_singleUser=Single-user case",
214 "Case_caseType_multiUser=Multi-user case"
217 if (fromString(typeName) == SINGLE_USER_CASE) {
218 return Bundle.Case_caseType_singleUser();
220 return Bundle.Case_caseType_multiUser();
230 this.typeName = typeName;
245 return (otherTypeName == null) ?
false : typeName.equals(otherTypeName);
402 .map(Events::toString)
403 .collect(Collectors.toSet()), listener);
414 .map(Events::toString)
415 .collect(Collectors.toSet()), listener);
438 eventTypes.forEach((
Events event) -> {
483 eventTypes.forEach((
Events event) -> {
497 return !(caseName.contains(
"\\") || caseName.contains(
"/") || caseName.contains(
":")
498 || caseName.contains(
"*") || caseName.contains(
"?") || caseName.contains(
"\"")
499 || caseName.contains(
"<") || caseName.contains(
">") || caseName.contains(
"|"));
551 "Case.exceptionMessage.emptyCaseName=Must specify a case name.",
552 "Case.exceptionMessage.emptyCaseDir=Must specify a case directory path."
556 throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseName());
558 if (caseDir.isEmpty()) {
559 throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseDir());
578 "# {0} - exception message",
"Case.exceptionMessage.failedToReadMetadata=Failed to read case metadata:\n{0}.",
579 "Case.exceptionMessage.cannotOpenMultiUserCaseNoSettings=Multi-user settings are missing (see Tools, Options, Multi-user tab), cannot open a multi-user case."
584 metadata =
new CaseMetadata(Paths.get(caseMetadataFilePath));
586 throw new CaseActionException(Bundle.Case_exceptionMessage_failedToReadMetadata(ex.getLocalizedMessage()), ex);
589 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotOpenMultiUserCaseNoSettings());
600 return currentCase != null;
617 throw new IllegalStateException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"), ex);
640 if (openCase == null) {
641 throw new NoCurrentCaseException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"));
656 "# {0} - exception message",
"Case.closeException.couldNotCloseCase=Error closing case: {0}",
657 "Case.progressIndicatorTitle.closingCase=Closing Case"
661 if (null == currentCase) {
667 logger.log(Level.INFO,
"Closing current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
670 logger.log(Level.INFO,
"Closed current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
671 }
catch (CaseActionException ex) {
692 if (null == currentCase) {
713 "Case.progressIndicatorTitle.deletingCase=Deleting Case",
714 "Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first.",
715 "Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
716 "Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service.",
717 "Case.exceptionMessage.failedToDeleteCoordinationServiceNodes=Failed to delete the coordination service nodes for the case."
723 if (null != currentCase) {
724 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
740 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
749 progressIndicator.
progress(Bundle.Case_progressMessage_checkingForOtherUser());
755 if (dirLock != null) {
758 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
763 throw new CaseActionException(Bundle.Case_exceptionMessage_failedToDeleteCoordinationServiceNodes(), ex);
766 deleteCoordinationServiceNodes(metadata, progressIndicator);
768 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
772 progressIndicator.
finish();
787 "Case.progressMessage.deletingCoordinationServiceNodes=Deleting coordination service nodes..."
789 static void deleteCoordinationServiceNodes(CaseMetadata metadata, ProgressIndicator progressIndicator)
throws CoordinationServiceException {
790 progressIndicator.progress(Bundle.Case_progressMessage_deletingCoordinationServiceNodes());
791 CoordinationService coordinationService;
792 coordinationService = CoordinationService.getInstance();
795 coordinationService.deleteNode(CategoryNode.CASES, resourcesLockNodePath);
796 }
catch (CoordinationServiceException ex) {
804 coordinationService.deleteNode(CategoryNode.CASES, caseDirectoryLockNodePath);
805 }
catch (CoordinationServiceException ex) {
824 "Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window"
828 if (null != currentCase) {
831 }
catch (CaseActionException ex) {
840 logger.log(Level.INFO,
"Opening {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
841 newCurrentCase.
open(isNewCase);
842 currentCase = newCurrentCase;
843 logger.log(Level.INFO,
"Opened {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
849 logger.log(Level.INFO, String.format(
"Cancelled opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()));
851 }
catch (CaseActionException ex) {
852 logger.log(Level.SEVERE, String.format(
"Error opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()), ex);
870 String uniqueCaseName = caseDisplayName.replaceAll(
"[^\\p{ASCII}]",
"_");
875 uniqueCaseName = uniqueCaseName.replaceAll(
"[\\p{Cntrl}]",
"_");
880 uniqueCaseName = uniqueCaseName.replaceAll(
"[ /?:'\"\\\\]",
"_");
885 uniqueCaseName = uniqueCaseName.toLowerCase();
890 SimpleDateFormat dateFormat =
new SimpleDateFormat(
"yyyyMMdd_HHmmss");
891 Date date =
new Date();
892 uniqueCaseName = uniqueCaseName +
"_" + dateFormat.format(date);
894 return uniqueCaseName;
911 File caseDir =
new File(caseDirPath);
912 if (caseDir.exists()) {
913 if (caseDir.isFile()) {
914 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existNotDir", caseDirPath));
915 }
else if (!caseDir.canRead() || !caseDir.canWrite()) {
916 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existCantRW", caseDirPath));
923 if (!caseDir.mkdirs()) {
924 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreate", caseDirPath));
932 String hostPathComponent =
"";
937 Path exportDir = Paths.get(caseDirPath, hostPathComponent, EXPORT_FOLDER);
938 if (!exportDir.toFile().mkdirs()) {
939 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", exportDir));
942 Path logsDir = Paths.get(caseDirPath, hostPathComponent, LOG_FOLDER);
943 if (!logsDir.toFile().mkdirs()) {
944 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", logsDir));
947 Path tempDir = Paths.get(caseDirPath, hostPathComponent, TEMP_FOLDER);
948 if (!tempDir.toFile().mkdirs()) {
949 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", tempDir));
952 Path cacheDir = Paths.get(caseDirPath, hostPathComponent, CACHE_FOLDER);
953 if (!cacheDir.toFile().mkdirs()) {
954 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", cacheDir));
957 Path moduleOutputDir = Paths.get(caseDirPath, hostPathComponent, MODULE_FOLDER);
958 if (!moduleOutputDir.toFile().mkdirs()) {
959 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateModDir", moduleOutputDir));
962 Path reportsDir = Paths.get(caseDirPath, hostPathComponent, REPORTS_FOLDER);
963 if (!reportsDir.toFile().mkdirs()) {
964 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateReportsDir", reportsDir));
975 static Map<Long, String> getImagePaths(SleuthkitCase db) {
976 Map<Long, String> imgPaths =
new HashMap<>();
978 Map<Long, List<String>> imgPathsList = db.getImagePaths();
979 for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
980 if (entry.getValue().size() > 0) {
981 imgPaths.put(entry.getKey(), entry.getValue().get(0));
984 }
catch (TskCoreException ex) {
985 logger.log(Level.SEVERE,
"Error getting image paths", ex);
1007 "Case.progressMessage.deletingTextIndex=Deleting text index...",
1008 "Case.progressMessage.deletingCaseDatabase=Deleting case database...",
1009 "Case.progressMessage.deletingCaseDirectory=Deleting case directory...",
1010 "Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
1014 boolean errorsOccurred =
false;
1021 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDatabase());
1022 CaseDbConnectionInfo db;
1024 Class.forName(
"org.postgresql.Driver");
1025 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
1026 Statement statement = connection.createStatement();) {
1028 statement.execute(deleteCommand);
1034 errorsOccurred =
true;
1043 progressIndicator.
progress(Bundle.Case_progressMessage_deletingTextIndex());
1048 searchService.deleteTextIndex(metadata);
1053 errorsOccurred =
true;
1062 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDirectory());
1067 errorsOccurred =
true;
1079 SwingUtilities.invokeLater(() -> {
1080 RecentCases.getInstance().removeRecentCase(metadata.
getCaseDisplayName(), metadata.getFilePath().toString());
1084 if (errorsOccurred) {
1085 throw new CaseActionException(Bundle.Case_exceptionMessage_errorsDeletingCase());
1100 "Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources"
1104 String resourcesNodeName = caseDir +
"_resources";
1107 }
catch (InterruptedException ex) {
1110 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock(), ex);
1129 SwingUtilities.invokeLater(() -> {
1135 String backupDbPath = caseDb.getBackupDatabasePath();
1136 if (null != backupDbPath) {
1137 JOptionPane.showMessageDialog(
1139 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.msg", backupDbPath),
1140 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.title"),
1141 JOptionPane.INFORMATION_MESSAGE);
1149 Map<Long, String> imgPaths = getImagePaths(caseDb);
1150 for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
1151 long obj_id = entry.getKey();
1152 String path = entry.getValue();
1155 int response = JOptionPane.showConfirmDialog(
1157 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.msg", path),
1158 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.title"),
1159 JOptionPane.YES_NO_OPTION);
1160 if (response == JOptionPane.YES_OPTION) {
1161 MissingImageDialog.makeDialog(obj_id, caseDb);
1163 logger.log(Level.SEVERE,
"User proceeding with missing image files");
1174 CallableSystemAction.get(CaseDetailsAction.class).setEnabled(
true);
1176 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
true);
1187 RecentCases.getInstance().addRecentCase(newCurrentCase.
getDisplayName(), newCurrentCase.getMetadata().getFilePath().toString());
1197 if (newCurrentCase.
hasData()) {
1216 SwingUtilities.invokeLater(() -> {
1226 CallableSystemAction.get(
AddImageAction.class).setEnabled(
false);
1228 CallableSystemAction.get(CaseDetailsAction.class).setEnabled(
false);
1230 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
false);
1255 File tempFolder =
new File(tempSubDirPath);
1256 if (tempFolder.isDirectory()) {
1257 File[] files = tempFolder.listFiles();
1258 if (files.length > 0) {
1259 for (File file : files) {
1260 if (file.isDirectory()) {
1392 hostPath = Paths.get(caseDirectory);
1394 if (!hostPath.toFile().exists()) {
1395 hostPath.toFile().mkdirs();
1397 return hostPath.toString();
1480 return path.subpath(path.getNameCount() - 2, path.getNameCount()).toString();
1482 return path.subpath(path.getNameCount() - 1, path.getNameCount()).toString();
1496 List<Content> list = caseDb.getRootObjects();
1497 hasDataSources = (list.size() > 0);
1507 Set<TimeZone> timezones =
new HashSet<>();
1510 final Content dataSource = c.getDataSource();
1511 if ((dataSource != null) && (dataSource instanceof Image)) {
1512 Image image = (Image) dataSource;
1513 timezones.add(TimeZone.getTimeZone(image.getTimeZone()));
1516 }
catch (TskCoreException ex) {
1517 logger.log(Level.SEVERE,
"Error getting data source time zones", ex);
1539 if (!hasDataSources) {
1542 }
catch (TskCoreException ex) {
1543 logger.log(Level.SEVERE,
"Error accessing case database", ex);
1653 logger.log(Level.WARNING,
"Unable to send notifcation regarding comment change due to no current case being open", ex);
1690 public void addReport(String localPath, String srcModuleName, String reportName)
throws TskCoreException {
1691 addReport(localPath, srcModuleName, reportName, null);
1708 public Report
addReport(String localPath, String srcModuleName, String reportName, Content parent)
throws TskCoreException {
1709 String normalizedLocalPath;
1711 if (localPath.toLowerCase().contains(
"http:")) {
1712 normalizedLocalPath = localPath;
1714 normalizedLocalPath = Paths.get(localPath).normalize().toString();
1716 }
catch (InvalidPathException ex) {
1717 String errorMsg =
"Invalid local path provided: " + localPath;
1718 throw new TskCoreException(errorMsg, ex);
1720 Report report = this.caseDb.addReport(normalizedLocalPath, srcModuleName, reportName, parent);
1734 return this.caseDb.getAllReports();
1745 public void deleteReports(Collection<? extends Report> reports)
throws TskCoreException {
1746 for (Report report : reports) {
1747 this.caseDb.deleteReport(report);
1769 "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata"
1771 void updateCaseDetails(CaseDetails caseDetails)
throws CaseActionException {
1774 metadata.setCaseDetails(caseDetails);
1775 }
catch (CaseMetadataException ex) {
1776 throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError(), ex);
1780 CoordinationService coordinationService = CoordinationService.getInstance();
1781 CaseNodeData nodeData =
new CaseNodeData(coordinationService.getNodeData(CategoryNode.CASES, metadata.
getCaseDirectory()));
1783 coordinationService.setNodeData(CategoryNode.CASES, metadata.
getCaseDirectory(), nodeData.toArray());
1784 }
catch (CoordinationServiceException | InterruptedException | IOException ex) {
1785 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotUpdateCaseNodeData(ex.getLocalizedMessage()), ex);
1788 if (!oldCaseDetails.getCaseNumber().equals(caseDetails.
getCaseNumber())) {
1789 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getCaseNumber(), caseDetails.
getCaseNumber()));
1791 if (!oldCaseDetails.getExaminerName().equals(caseDetails.
getExaminerName())) {
1792 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getExaminerName(), caseDetails.
getExaminerName()));
1795 eventPublisher.
publish(
new AutopsyEvent(Events.NAME.toString(), oldCaseDetails.getCaseDisplayName(), caseDetails.
getCaseDisplayName()));
1797 eventPublisher.
publish(
new AutopsyEvent(Events.CASE_DETAILS.toString(), oldCaseDetails, caseDetails));
1798 if (RuntimeProperties.runningWithGUI()) {
1799 SwingUtilities.invokeLater(() -> {
1802 RecentCases.getInstance().updateRecentCase(oldCaseDetails.getCaseDisplayName(), metadata.getFilePath().toString(), caseDetails.
getCaseDisplayName(), metadata.getFilePath().toString());
1803 }
catch (Exception ex) {
1804 logger.log(Level.SEVERE,
"Error updating case name in UI", ex);
1832 metadata = caseMetaData;
1851 "Case.progressIndicatorTitle.creatingCase=Creating Case",
1852 "Case.progressIndicatorTitle.openingCase=Opening Case",
1853 "Case.progressIndicatorCancelButton.label=Cancel",
1854 "Case.progressMessage.preparing=Preparing...",
1855 "Case.progressMessage.preparingToOpenCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>",
1856 "Case.progressMessage.cancelling=Cancelling...",
1857 "Case.exceptionMessage.cancelledByUser=Cancelled by user.",
1858 "# {0} - exception message",
"Case.exceptionMessage.execExceptionWrapperMessage={0}"
1860 private void open(
boolean isNewCase)
throws CaseActionException {
1869 String progressIndicatorTitle = isNewCase ? Bundle.Case_progressIndicatorTitle_creatingCase() : Bundle.Case_progressIndicatorTitle_openingCase();
1872 progressIndicatorTitle,
1873 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1874 Bundle.Case_progressIndicatorCancelButton_label(),
1875 cancelButtonListener);
1879 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1897 caseLockingExecutor = Executors.newSingleThreadExecutor(threadFactory);
1898 Future<Void> future = caseLockingExecutor.submit(() -> {
1900 open(isNewCase, progressIndicator);
1909 progressIndicator.
progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
1912 if (null == resourcesLock) {
1913 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
1915 open(isNewCase, progressIndicator);
1916 }
catch (CaseActionException ex) {
1923 if (null != cancelButtonListener) {
1932 }
catch (InterruptedException discarded) {
1941 if (null != cancelButtonListener) {
1944 future.cancel(
true);
1947 }
catch (CancellationException discarded) {
1957 }
catch (ExecutionException ex) {
1966 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
1968 progressIndicator.
finish();
2016 }
catch (CaseActionException ex) {
2025 }
catch (InterruptedException discarded) {
2027 close(progressIndicator);
2042 public SleuthkitCase
createPortableCase(String caseName, File portableCaseFolder)
throws TskCoreException {
2044 if (portableCaseFolder.exists()) {
2045 throw new TskCoreException(
"Portable case folder " + portableCaseFolder.toString() +
" already exists");
2047 if (!portableCaseFolder.mkdirs()) {
2048 throw new TskCoreException(
"Error creating portable case folder " + portableCaseFolder.toString());
2056 portableCaseMetadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
2058 throw new TskCoreException(
"Error creating case metadata", ex);
2062 SleuthkitCase portableSleuthkitCase;
2064 portableSleuthkitCase = SleuthkitCase.newCase(dbFilePath);
2066 return portableSleuthkitCase;
2079 if (Thread.currentThread().isInterrupted()) {
2080 throw new CaseActionCancelledException(Bundle.Case_exceptionMessage_cancelledByUser());
2098 "Case.progressMessage.creatingCaseDirectory=Creating case directory..."
2101 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
2103 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
2115 "Case.progressMessage.switchingLogDirectory=Switching log directory..."
2118 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2134 "Case.progressMessage.savingCaseMetadata=Saving case metadata to file...",
2135 "# {0} - exception message",
"Case.exceptionMessage.couldNotSaveCaseMetadata=Failed to save case metadata:\n{0}."
2138 progressIndicator.
progress(Bundle.Case_progressMessage_savingCaseMetadata());
2140 this.metadata.writeToFile();
2142 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotSaveCaseMetadata(ex.getLocalizedMessage()), ex);
2158 "Case.progressMessage.creatingCaseNodeData=Creating coordination service node data...",
2159 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreateCaseNodeData=Failed to create coordination service node data:\n{0}."
2163 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseNodeData());
2169 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseNodeData(ex.getLocalizedMessage()), ex);
2184 "Case.progressMessage.updatingCaseNodeData=Updating coordination service node data...",
2185 "# {0} - exception message",
"Case.exceptionMessage.couldNotUpdateCaseNodeData=Failed to update coordination service node data:\n{0}."
2189 progressIndicator.
progress(Bundle.Case_progressMessage_updatingCaseNodeData());
2197 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotUpdateCaseNodeData(ex.getLocalizedMessage()), ex);
2209 "Case.progressMessage.clearingTempDirectory=Clearing case temp directory..."
2215 progressIndicator.
progress(Bundle.Case_progressMessage_clearingTempDirectory());
2231 "Case.progressMessage.creatingCaseDatabase=Creating case database...",
2232 "# {0} - exception message",
"Case.exceptionMessage.couldNotGetDbServerConnectionInfo=Failed to get case database server conneciton info:\n{0}.",
2233 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}.",
2234 "# {0} - exception message",
"Case.exceptionMessage.couldNotSaveDbNameToMetadataFile=Failed to save case database name to case metadata file:\n{0}."
2237 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDatabase());
2246 metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
2254 metadata.setCaseDatabaseName(caseDb.getDatabaseName());
2256 }
catch (TskCoreException ex) {
2257 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(ex.getLocalizedMessage()), ex);
2259 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotGetDbServerConnectionInfo(ex.getLocalizedMessage()), ex);
2261 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotSaveDbNameToMetadataFile(ex.getLocalizedMessage()), ex);
2277 "Case.progressMessage.openingCaseDatabase=Opening case database...",
2278 "# {0} - exception message",
"Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database:\n{0}.",
2279 "# {0} - exception message",
"Case.exceptionMessage.unsupportedSchemaVersionMessage=Unsupported case database schema version:\n{0}.",
2280 "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User."
2283 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseDatabase());
2287 caseDb = SleuthkitCase.openCase(Paths.get(metadata.
getCaseDirectory(), databaseName).toString());
2291 throw new CaseActionException(Case_open_exception_multiUserCaseNotEnabled());
2293 }
catch (TskUnsupportedSchemaVersionException ex) {
2294 throw new CaseActionException(Bundle.Case_exceptionMessage_unsupportedSchemaVersionMessage(ex.getLocalizedMessage()), ex);
2296 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotGetDbServerConnectionInfo(ex.getLocalizedMessage()), ex);
2297 }
catch (TskCoreException ex) {
2298 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(ex.getLocalizedMessage()), ex);
2309 "Case.progressMessage.openingCaseLevelServices=Opening case-level services...",})
2311 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseLevelServices());
2312 this.caseServices =
new Services(caseDb);
2326 @NbBundle.Messages({
2327 "Case.progressMessage.openingApplicationServiceResources=Opening application service case resources...",
2328 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.title={0} Opening Case Resources",
2329 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.cancellingMessage=Cancelling opening case resources by {0}...",
2330 "# {0} - service name",
"Case.servicesException.notificationTitle={0} Error"
2333 progressIndicator.
progress(Bundle.Case_progressMessage_openingApplicationServiceResources());
2351 cancelButtonListener =
new CancelButtonListener(Bundle.Case_serviceOpenCaseResourcesProgressIndicator_cancellingMessage(service.getServiceName()));
2354 Bundle.Case_serviceOpenCaseResourcesProgressIndicator_title(service.getServiceName()),
2355 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
2356 Bundle.Case_progressIndicatorCancelButton_label(),
2357 cancelButtonListener);
2361 appServiceProgressIndicator.
start(Bundle.Case_progressMessage_preparing());
2363 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2364 threadNameSuffix = threadNameSuffix.toLowerCase();
2366 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2367 Future<Void> future = executor.submit(() -> {
2368 service.openCaseResources(context);
2371 if (null != cancelButtonListener) {
2383 }
catch (InterruptedException discarded) {
2388 future.cancel(
true);
2389 }
catch (CancellationException discarded) {
2397 }
catch (ExecutionException ex) {
2404 Case.
logger.log(Level.SEVERE, String.format(
"%s failed to open case resources for %s", service.getServiceName(), this.
getDisplayName()), ex);
2406 SwingUtilities.invokeLater(() -> {
2418 appServiceProgressIndicator.
finish();
2436 "Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",
2437 "# {0} - exception message",
"Case.exceptionMessage.couldNotOpenRemoteEventChannel=Failed to open remote events channel:\n{0}.",
2438 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreatCollaborationMonitor=Failed to create collaboration monitor:\n{0}."
2442 progressIndicator.
progress(Bundle.Case_progressMessage_settingUpNetworkCommunications());
2446 collaborationMonitor =
new CollaborationMonitor(metadata.
getCaseName());
2448 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenRemoteEventChannel(ex.getLocalizedMessage()), ex);
2449 }
catch (CollaborationMonitor.CollaborationMonitorException ex) {
2450 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreatCollaborationMonitor(ex.getLocalizedMessage()), ex);
2463 private void close() throws CaseActionException {
2472 Bundle.Case_progressIndicatorTitle_closingCase());
2476 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2485 Future<Void> future = caseLockingExecutor.submit(() -> {
2487 close(progressIndicator);
2494 progressIndicator.
progress(Bundle.Case_progressMessage_preparing());
2496 if (null == resourcesLock) {
2497 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
2499 close(progressIndicator);
2513 }
catch (InterruptedException | CancellationException unused) {
2520 }
catch (ExecutionException ex) {
2521 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
2524 progressIndicator.
finish();
2534 "Case.progressMessage.shuttingDownNetworkCommunications=Shutting down network communications...",
2535 "Case.progressMessage.closingApplicationServiceResources=Closing case-specific application service resources...",
2536 "Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
2537 "Case.progressMessage.closingCaseDatabase=Closing case database..."
2547 progressIndicator.
progress(Bundle.Case_progressMessage_shuttingDownNetworkCommunications());
2548 if (null != collaborationMonitor) {
2549 collaborationMonitor.shutdown();
2558 progressIndicator.
progress(Bundle.Case_progressMessage_closingApplicationServiceResources());
2564 if (null != caseServices) {
2565 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseLevelServices());
2567 this.caseServices.
close();
2568 }
catch (IOException ex) {
2569 logger.log(Level.SEVERE, String.format(
"Error closing internal case services for %s at %s",
this.getName(), this.
getCaseDirectory()), ex);
2576 if (null != caseDb) {
2577 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseDatabase());
2584 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2593 "# {0} - serviceName",
"Case.serviceCloseResourcesProgressIndicator.title={0} Closing Case Resources",
2594 "# {0} - service name",
"# {1} - exception message",
"Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1}"
2606 Bundle.Case_serviceCloseResourcesProgressIndicator_title(service.getServiceName()));
2610 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2612 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2613 threadNameSuffix = threadNameSuffix.toLowerCase();
2615 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2616 Future<Void> future = executor.submit(() -> {
2617 service.closeCaseResources(context);
2622 }
catch (InterruptedException ex) {
2623 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to close case resources", service.getServiceName()), ex);
2624 }
catch (CancellationException ex) {
2625 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected cancellation while waiting on %s service to close case resources", service.getServiceName()), ex);
2626 }
catch (ExecutionException ex) {
2627 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
2630 Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
2631 Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
2635 progressIndicator.
finish();
2648 @Messages({
"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory"})
2653 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
2656 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
2671 logger.log(Level.SEVERE, String.format(
"Failed to release shared case directory lock for %s", caseDir), ex);
2684 if (!subDirectory.exists()) {
2685 subDirectory.mkdirs();
2687 return subDirectory.toString();
2778 ((ModalDialogProgressIndicator) progressIndicator).setCancelling(cancellationMessage);
2807 return new Thread(task, threadName);
2844 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
throws CaseActionException {
2869 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner,
CaseType caseType)
throws CaseActionException {
2885 public static void open(String caseMetadataFilePath)
throws CaseActionException {
2942 return new File(filePath).isFile();
2981 return "ModuleOutput";
2994 public static PropertyChangeSupport
2996 return new PropertyChangeSupport(
Case.class
3028 public Image
addImage(String imgPath,
long imgId, String timeZone)
throws CaseActionException {
3030 Image newDataSource = caseDb.getImageById(imgId);
3032 return newDataSource;
3033 }
catch (TskCoreException ex) {
3034 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.addImg.exception.msg"), ex);
3061 public void deleteReports(Collection<? extends Report> reports,
boolean deleteFromDisk)
throws TskCoreException {
String getLogDirectoryPath()
static final AutopsyEventPublisher eventPublisher
List< Content > getDataSources()
String getModuleOutputDirectoryRelativePath()
void notifyContentTagDeleted(ContentTag deletedTag)
Case(CaseMetadata caseMetaData)
static CaseType fromString(String typeName)
static void checkForUserCancellation()
static final String CASE_ACTION_THREAD_NAME
void publishLocally(AutopsyEvent event)
static void createAsCurrentCase(CaseType caseType, String caseDir, CaseDetails caseDetails)
void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag)
String getExaminerPhone()
Set< TimeZone > getTimeZones()
static String getNameForTitle()
Image addImage(String imgPath, long imgId, String timeZone)
long getElapsedTimeSecs()
static synchronized IngestManager getInstance()
static CoordinationService.Lock acquireExclusiveCaseResourcesLock(String caseDir)
static boolean runningWithGUI
static void closeCurrentCase()
String getTempDirectory()
static boolean existsCurrentCase()
static void removePropertyChangeListener(PropertyChangeListener listener)
void start(String message, int totalWorkUnits)
static final Logger logger
void publish(AutopsyEvent event)
static final int RESOURCES_LOCK_TIMOUT_HOURS
String getLocalizedDisplayName()
ADDING_DATA_SOURCE_FAILED
static final String EXPORT_FOLDER
static void createCaseDirectory(String caseDirPath, CaseType caseType)
String getCaseDirectory()
static String getAppName()
void notifyTagDefinitionChanged(String changedTagName)
static volatile Frame mainFrame
static String convertTimeZone(String timeZoneId)
static boolean driveExists(String path)
static void openCoreWindows()
void addSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
synchronized static void setLogDirectory(String directoryPath)
void notifyCentralRepoCommentChanged(long contentId, String newComment)
TaskThreadFactory(String threadName)
static final String CACHE_FOLDER
static String getAutopsyVersion()
CaseType(String typeName)
Case(CaseType caseType, String caseDir, CaseDetails caseDetails)
String getReportDirectory()
static boolean getIsMultiUserModeEnabled()
void addReport(String localPath, String srcModuleName, String reportName)
static void updateGUIForCaseOpened(Case newCurrentCase)
void notifyDataSourceNameChanged(Content dataSource, String newName)
static CaseDbConnectionInfo getDatabaseConnectionInfo()
String getModulesOutputDirAbsPath()
static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType)
void closeAppServiceCaseResources()
static final String SINGLE_USER_CASE_DB_NAME
byte[] getNodeData(CategoryNode category, String nodePath)
static void deleteCase(CaseMetadata metadata)
void deleteReports(Collection<?extends Report > reports, boolean deleteFromDisk)
synchronized void closeRemoteEventChannel()
volatile ExecutorService caseLockingExecutor
List< Report > getAllReports()
static void clearTempSubDir(String tempSubDirPath)
static boolean isValidName(String caseName)
void acquireSharedCaseDirLock(String caseDir)
void openCaseDataBase(ProgressIndicator progressIndicator)
void createCaseDirectoryIfDoesNotExist(ProgressIndicator progressIndicator)
CollaborationMonitor collaborationMonitor
void openCommunicationChannels(ProgressIndicator progressIndicator)
void releaseSharedCaseDirLock(String caseDir)
static void shutDownTaskExecutor(ExecutorService executor)
static void closeCoreWindows()
ProgressIndicator getProgressIndicator()
static String getModulesOutputDirRelPath()
void saveCaseMetadataToFile(ProgressIndicator progressIndicator)
Set< TimeZone > getTimeZone()
static final String MODULE_FOLDER
void openCaseLevelServices(ProgressIndicator progressIndicator)
static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
synchronized void openRemoteEventChannel(String channelName)
String getCaseDisplayName()
void createCaseNodeData(ProgressIndicator progressIndicator)
static void invokeStartupDialog()
static String displayNameToUniqueName(String caseDisplayName)
void open(boolean isNewCase)
static void openAsCurrentCase(String caseMetadataFilePath)
static void removeEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
Lock tryGetExclusiveLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
void setLastAccessDate(Date lastAccessDate)
static final int DIR_LOCK_TIMOUT_HOURS
void close(ProgressIndicator progressIndicator)
void setNodeData(CategoryNode category, String nodePath, byte[] data)
SleuthkitCase getSleuthkitCase()
void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag)
static PropertyChangeSupport getPropertyChangeSupport()
String getCacheDirectory()
static void addPropertyChangeListener(PropertyChangeListener listener)
void removeSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
String getModuleDirectory()
void createCaseDatabase(ProgressIndicator progressIndicator)
void openAppServiceCaseResources(ProgressIndicator progressIndicator)
Thread newThread(Runnable task)
static void removeEventSubscriber(String eventName, PropertyChangeListener subscriber)
void switchLoggingToCaseLogsDirectory(ProgressIndicator progressIndicator)
final CaseMetadata metadata
void deleteTempfilesFromCaseDirectory(ProgressIndicator progressIndicator)
void deleteReports(Collection<?extends Report > reports)
void notifyDataSourceAdded(Content dataSource, UUID addingDataSourceEventId)
Report addReport(String localPath, String srcModuleName, String reportName, Content parent)
static boolean pathExists(String filePath)
SleuthkitCase createPortableCase(String caseName, File portableCaseFolder)
BLACKBOARD_ARTIFACT_TAG_ADDED
static void open(String caseMetadataFilePath)
static void openAsCurrentCase(Case newCurrentCase, boolean isNewCase)
String getOutputDirectory()
static void error(String title, String message)
String getOrCreateSubdirectory(String subDirectoryName)
boolean equalsName(String otherTypeName)
static final String EVENT_CHANNEL_NAME
static Case getCurrentCase()
static String getLocalHostName()
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static String convertToAlphaNumericFormat(String timeZoneId)
static final String LOG_FOLDER
Lock tryGetSharedLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
String getConfigDirectory()
static String getAppName()
static synchronized CoordinationService getInstance()
static volatile Case currentCase
static String getVersion()
String getExportDirectory()
static void updateGUIForCaseClosed()
void notifyAddingDataSource(UUID eventId)
CoordinationService.Lock caseDirLock
static void addEventSubscriber(String eventName, PropertyChangeListener subscriber)
void notifyContentTagAdded(ContentTag newTag)
void cancelAllIngestJobs(IngestJob.CancellationReason reason)
static final String CASE_RESOURCES_THREAD_NAME
static StartupWindowProvider getInstance()
static void deleteCurrentCase()
static boolean deleteDir(File dirPath)
static void createAsCurrentCase(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType)
void notifyFailedAddingDataSource(UUID addingDataSourceEventId)
static final String CONFIG_FOLDER
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static final Object caseActionSerializationLock
void open(boolean isNewCase, ProgressIndicator progressIndicator)
static boolean isCaseOpen()
String getTextIndexName()
static final String REPORTS_FOLDER
void progress(String message)
static final String TEMP_FOLDER
BLACKBOARD_ARTIFACT_TAG_DELETED
static void addEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
void updateCaseNodeData(ProgressIndicator progressIndicator)
static void deleteCase(CaseMetadata metadata, ProgressIndicator progressIndicator)
static void error(String message)
String getExaminerEmail()