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()