19 package org.sleuthkit.autopsy.casemodule;
 
   21 import java.awt.Frame;
 
   22 import java.awt.event.ActionEvent;
 
   23 import java.awt.event.ActionListener;
 
   24 import java.beans.PropertyChangeListener;
 
   25 import java.beans.PropertyChangeSupport;
 
   27 import java.io.IOException;
 
   28 import java.lang.reflect.InvocationTargetException;
 
   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.Statement;
 
   35 import java.text.SimpleDateFormat;
 
   36 import java.util.Collection;
 
   37 import java.util.Date;
 
   38 import java.util.HashMap;
 
   39 import java.util.HashSet;
 
   40 import java.util.List;
 
   42 import java.util.MissingResourceException;
 
   44 import java.util.TimeZone;
 
   45 import java.util.UUID;
 
   46 import java.util.concurrent.CancellationException;
 
   47 import java.util.concurrent.ExecutionException;
 
   48 import java.util.concurrent.ExecutorService;
 
   49 import java.util.concurrent.Executors;
 
   50 import java.util.concurrent.Future;
 
   51 import java.util.concurrent.TimeUnit;
 
   52 import java.util.logging.Level;
 
   53 import java.util.stream.Collectors;
 
   54 import java.util.stream.Stream;
 
   55 import javax.annotation.concurrent.GuardedBy;
 
   56 import javax.swing.JOptionPane;
 
   57 import javax.swing.SwingUtilities;
 
   58 import org.openide.util.Lookup;
 
   59 import org.openide.util.NbBundle;
 
   60 import org.openide.util.NbBundle.Messages;
 
   61 import org.openide.util.actions.CallableSystemAction;
 
   62 import org.openide.windows.WindowManager;
 
  142     @GuardedBy(
"currentCaseWriteLock")
 
  155     @GuardedBy("currentCaseWriteLock")
 
  157     @GuardedBy("currentCaseWriteLock")
 
  190             if (typeName != null) {
 
  191                 for (CaseType c : CaseType.values()) {
 
  192                     if (typeName.equalsIgnoreCase(c.toString())) {
 
  216             "Case_caseType_singleUser=Single-user case",
 
  217             "Case_caseType_multiUser=Multi-user case" 
  220             if (fromString(typeName) == SINGLE_USER_CASE) {
 
  221                 return Bundle.Case_caseType_singleUser();
 
  223                 return Bundle.Case_caseType_multiUser();
 
  233             this.typeName = typeName;
 
  248             return (otherTypeName == null) ? 
false : typeName.equals(otherTypeName);
 
  374                 .map(Events::toString)
 
  375                 .collect(Collectors.toSet()), listener);
 
  386                 .map(Events::toString)
 
  387                 .collect(Collectors.toSet()), listener);
 
  439         return !(caseName.contains(
"\\") || caseName.contains(
"/") || caseName.contains(
":")
 
  440                 || caseName.contains(
"*") || caseName.contains(
"?") || caseName.contains(
"\"")
 
  441                 || caseName.contains(
"<") || caseName.contains(
">") || caseName.contains(
"|"));
 
  467         "# {0} - exception message", 
"Case.exceptionMessage.wrapperMessage={0}" 
  475             if (null != currentCase) {
 
  476                 String previousCaseDisplayName = currentCase.getDisplayName();
 
  477                 String previousCaseName = currentCase.getName();
 
  478                 String previousCaseDir = currentCase.getCaseDirectory();
 
  482                     logger.log(Level.SEVERE, String.format(
"Error closing the previous current case %s (%s) in %s", previousCaseDisplayName, previousCaseName, previousCaseDir), ex); 
 
  486             logger.log(Level.INFO, 
"Creating current case {0} in {1}", 
new Object[]{caseDisplayName, caseDir}); 
 
  488             newCurrentCase.
create(caseType, caseDir, caseDisplayName, caseNumber, examiner);
 
  489             currentCase = newCurrentCase;
 
  490             logger.log(Level.INFO, 
"Created currrent case {0} ({1}) in {2}", 
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()}); 
 
  512         "# {0} - exception message", 
"Case.openException.couldNotOpenCase=Could not open case: {0}",
 
  513         "Case.progressIndicatorTitle.openingCase=Opening Case",
 
  514         "Case.exceptionMessage.failedToReadMetadata=Failed to read metadata." 
  522             if (null != currentCase) {
 
  526                     logger.log(Level.SEVERE, 
"Error closing the previous current case", ex);
 
  531             logger.log(Level.INFO, 
"Opening case with metadata file path {0} as current case", caseMetadataFilePath); 
 
  532             newCurrentCase.
open(Paths.get(caseMetadataFilePath));
 
  533             currentCase = newCurrentCase;
 
  534             logger.log(Level.INFO, 
"Opened case with metadata file path {0} as current case", caseMetadataFilePath); 
 
  548         return currentCase != null;
 
  560         if (null != caseToReturn) {
 
  563             throw new IllegalStateException(NbBundle.getMessage(
Case.class, 
"Case.getCurCase.exception.noneOpen"));
 
  576         "# {0} - exception message", 
"Case.closeException.couldNotCloseCase=Error closing case: {0}",
 
  577         "Case.progressIndicatorTitle.closingCase=Closing Case" 
  581             if (null == currentCase) {
 
  584             String caseName = currentCase.getName();
 
  585             String caseDir = currentCase.getCaseDirectory();
 
  589                 logger.log(Level.INFO, 
"Closing current case {0} in {1}", 
new Object[]{caseName, caseDir}); 
 
  597                 logger.log(Level.INFO, 
"Closed current case {0} in {1}", 
new Object[]{caseName, caseDir}); 
 
  618             if (null == currentCase) {
 
  639         "# {0} - exception message", 
"Case.deleteException.couldNotDeleteCase=Could not delete case: {0}",
 
  640         "Case.progressIndicatorTitle.deletingCase=Deleting Case",
 
  641         "Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first",
 
  642         "Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
 
  643         "Case.progressMessage.deletingTextIndex=Deleting text index...",
 
  644         "Case.progressMessage.deletingCaseDatabase=Deleting case database...",
 
  645         "Case.exceptionMessage.cancelled=Cancelled by user" 
  650                 throw new CaseActionException(Bundle.Case_deleteException_couldNotDeleteCase(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase()));
 
  662                     Bundle.Case_progressIndicatorTitle_deletingCase());
 
  666         progressIndicator.
start(Bundle.Case_progressMessage_preparing());
 
  668         logger.log(Level.INFO, 
"Deleting case with metadata file path {0}", metadata.getFilePath()); 
 
  669         ExecutorService executor = Executors.newSingleThreadExecutor();
 
  670         Future<Void> future = executor.submit(() -> {
 
  671             if (CaseType.SINGLE_USER_CASE == metadata.
getCaseType()) {
 
  678                 progressIndicator.
start(Bundle.Case_progressMessage_checkingForOtherUser());
 
  680                     assert (null != dirLock);
 
  685                     progressIndicator.
start(Bundle.Case_progressMessage_deletingTextIndex());
 
  687                         searchService.deleteTextIndex(metadata);
 
  690                     if (CaseType.MULTI_USER_CASE == metadata.
getCaseType()) {
 
  696                         progressIndicator.
start(Bundle.Case_progressMessage_deletingCaseDatabase());
 
  698                         Class.forName(
"org.postgresql.Driver"); 
 
  700                                 Statement statement = connection.createStatement();) {
 
  702                             statement.execute(deleteCommand);
 
  714             logger.log(Level.INFO, 
"Deleted case with metadata file path {0}", metadata.getFilePath()); 
 
  715         } 
catch (InterruptedException ex) {
 
  716             throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getMessage()), ex);
 
  717         } 
catch (ExecutionException ex) {
 
  718             throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getCause().getMessage()), ex);
 
  719         } 
catch (CancellationException ex) {
 
  738         String uniqueCaseName = caseDisplayName.replaceAll(
"[^\\p{ASCII}]", 
"_"); 
 
  743         uniqueCaseName = uniqueCaseName.replaceAll(
"[\\p{Cntrl}]", 
"_"); 
 
  748         uniqueCaseName = uniqueCaseName.replaceAll(
"[ /?:'\"\\\\]", 
"_"); 
 
  753         uniqueCaseName = uniqueCaseName.toLowerCase();
 
  758         SimpleDateFormat dateFormat = 
new SimpleDateFormat(
"yyyyMMdd_HHmmss");
 
  759         Date date = 
new Date();
 
  760         uniqueCaseName = uniqueCaseName + 
"_" + dateFormat.format(date);
 
  762         return uniqueCaseName;
 
  773     static void createCaseDirectory(String caseDir, CaseType caseType) 
throws CaseActionException {
 
  775         File caseDirF = 
new File(caseDir);
 
  777         if (caseDirF.exists()) {
 
  778             if (caseDirF.isFile()) {
 
  780                         NbBundle.getMessage(
Case.class, 
"Case.createCaseDir.exception.existNotDir", caseDir));
 
  782             } 
else if (!caseDirF.canRead() || !caseDirF.canWrite()) {
 
  783                 throw new CaseActionException(
 
  784                         NbBundle.getMessage(
Case.class, 
"Case.createCaseDir.exception.existCantRW", caseDir));
 
  789             boolean result = (caseDirF).mkdirs(); 
 
  791             if (result == 
false) {
 
  792                 throw new CaseActionException(
 
  793                         NbBundle.getMessage(
Case.class, 
"Case.createCaseDir.exception.cantCreate", caseDir));
 
  797             String hostClause = 
"";
 
  800                 hostClause = File.separator + NetworkUtils.getLocalHostName();
 
  802             result = result && (
new File(caseDir + hostClause + File.separator + EXPORT_FOLDER)).mkdirs()
 
  803                     && (
new File(caseDir + hostClause + File.separator + LOG_FOLDER)).mkdirs()
 
  804                     && (
new File(caseDir + hostClause + File.separator + TEMP_FOLDER)).mkdirs()
 
  805                     && (
new File(caseDir + hostClause + File.separator + CACHE_FOLDER)).mkdirs();
 
  807             if (result == 
false) {
 
  808                 throw new CaseActionException(
 
  809                         NbBundle.getMessage(
Case.class, 
"Case.createCaseDir.exception.cantCreateCaseDir", caseDir));
 
  812             final String modulesOutDir = caseDir + hostClause + File.separator + 
MODULE_FOLDER;
 
  813             result = 
new File(modulesOutDir).mkdir();
 
  815             if (result == 
false) {
 
  816                 throw new CaseActionException(
 
  817                         NbBundle.getMessage(
Case.class, 
"Case.createCaseDir.exception.cantCreateModDir",
 
  821             final String reportsOutDir = caseDir + hostClause + File.separator + 
REPORTS_FOLDER;
 
  822             result = 
new File(reportsOutDir).mkdir();
 
  824             if (result == 
false) {
 
  825                 throw new CaseActionException(
 
  826                         NbBundle.getMessage(
Case.class, 
"Case.createCaseDir.exception.cantCreateReportsDir",
 
  831         } 
catch (MissingResourceException | CaseActionException e) {
 
  832             throw new CaseActionException(
 
  833                     NbBundle.getMessage(
Case.class, 
"Case.createCaseDir.exception.gen", caseDir), e);
 
  844     static Map<Long, String> getImagePaths(SleuthkitCase db) {
 
  845         Map<Long, String> imgPaths = 
new HashMap<>();
 
  847             Map<Long, List<String>> imgPathsList = db.getImagePaths();
 
  848             for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
 
  849                 if (entry.getValue().size() > 0) {
 
  850                     imgPaths.put(entry.getKey(), entry.getValue().get(0));
 
  853         } 
catch (TskCoreException ex) {
 
  854             logger.log(Level.SEVERE, 
"Error getting image paths", ex); 
 
  868         "Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window" 
  873                 SwingUtilities.invokeAndWait(() -> {
 
  874                     mainFrame = WindowManager.getDefault().getMainWindow();
 
  885                     appName = mainFrame.getTitle();
 
  887             } 
catch (InterruptedException | InvocationTargetException ex) {
 
  888                 throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(Bundle.Case_exceptionMessage_cannotLocateMainWindow()), ex);
 
  901         "Case.progressMessage.deletingCaseDirectory=Deleting case directory..." 
  907         progressIndicator.
start(Bundle.Case_progressMessage_deletingCaseDirectory());
 
  909             logger.log(Level.SEVERE, 
"Failed to fully delete case directory {0}", metadata.
getCaseDirectory());
 
  916             SwingUtilities.invokeLater(() -> {
 
  917                 RecentCases.getInstance().removeRecentCase(metadata.
getCaseDisplayName(), metadata.getFilePath().toString());
 
  932     @Messages({
"Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources"})
 
  935             String resourcesNodeName = caseDir + 
"_resources";
 
  938                 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
 
  943             throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock(), ex);
 
  951         SwingUtilities.invokeLater(() -> {
 
  958             if (null != backupDbPath) {
 
  959                 JOptionPane.showMessageDialog(
 
  960                         WindowManager.getDefault().getMainWindow(),
 
  961                         NbBundle.getMessage(
Case.class, 
"Case.open.msgDlg.updated.msg", backupDbPath),
 
  962                         NbBundle.getMessage(
Case.class, 
"Case.open.msgDlg.updated.title"),
 
  963                         JOptionPane.INFORMATION_MESSAGE);
 
  971             Map<Long, String> imgPaths = getImagePaths(caseDb);
 
  972             for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
 
  973                 long obj_id = entry.getKey();
 
  974                 String path = entry.getValue();
 
  978                     int response = JOptionPane.showConfirmDialog(
 
  979                             WindowManager.getDefault().getMainWindow(),
 
  980                             NbBundle.getMessage(
Case.class, 
"Case.checkImgExist.confDlg.doesntExist.msg", appName, path),
 
  981                             NbBundle.getMessage(
Case.class, 
"Case.checkImgExist.confDlg.doesntExist.title"),
 
  982                             JOptionPane.YES_NO_OPTION);
 
  983                     if (response == JOptionPane.YES_OPTION) {
 
  984                         MissingImageDialog.makeDialog(obj_id, caseDb);
 
  986                         logger.log(Level.SEVERE, 
"User proceeding with missing image files"); 
 
 1000             CallableSystemAction
 
 1001                     .get(CasePropertiesAction.class
 
 1003             CallableSystemAction
 
 1004                     .get(CaseDeleteAction.class
 
 1006             CallableSystemAction
 
 1009             CallableSystemAction
 
 1011                     ).setEnabled(
false);
 
 1018             RecentCases.getInstance().addRecentCase(newCurrentCase.
getDisplayName(), newCurrentCase.getCaseMetadata().getFilePath().toString());
 
 1024             if (newCurrentCase.
hasData()) {
 
 1040         SwingUtilities.invokeLater(() -> {
 
 1051             CallableSystemAction
 
 1053                     ).setEnabled(
false);
 
 1054             CallableSystemAction
 
 1056                     ).setEnabled(
false);
 
 1057             CallableSystemAction
 
 1058                     .get(CasePropertiesAction.class
 
 1059                     ).setEnabled(
false);
 
 1060             CallableSystemAction
 
 1061                     .get(CaseDeleteAction.class
 
 1062                     ).setEnabled(
false);
 
 1063             CallableSystemAction
 
 1065                     ).setEnabled(
false);
 
 1066             CallableSystemAction
 
 1068                     ).setEnabled(
false);
 
 1080             Frame mainWindow = WindowManager.getDefault().getMainWindow();
 
 1081             mainWindow.setTitle(appName);
 
 1091         if (!caseName.isEmpty()) {
 
 1092             Frame frame = WindowManager.getDefault().getMainWindow();
 
 1093             frame.setTitle(caseName + 
" - " + appName);
 
 1101         File tempFolder = 
new File(tempSubDirPath);
 
 1102         if (tempFolder.isDirectory()) {
 
 1103             File[] files = tempFolder.listFiles();
 
 1104             if (files.length > 0) {
 
 1105                 for (File file : files) {
 
 1106                     if (file.isDirectory()) {
 
 1149         return getCaseMetadata().getCreatedDate();
 
 1176         return caseMetadata.getCaseNumber();
 
 1185         return caseMetadata.getExaminer();
 
 1194         return caseMetadata.getCaseDirectory();
 
 1211             hostPath = Paths.get(caseDirectory);
 
 1213         if (!hostPath.toFile().exists()) {
 
 1214             hostPath.toFile().mkdirs();
 
 1216         return hostPath.toString();
 
 1289             return path.subpath(path.getNameCount() - 2, path.getNameCount()).toString();
 
 1291             return path.subpath(path.getNameCount() - 1, path.getNameCount()).toString();
 
 1305         List<Content> list = caseDb.getRootObjects();
 
 1306         hasDataSources = (list.size() > 0);
 
 1316         Set<TimeZone> timezones = 
new HashSet<>();
 
 1320                 if ((dataSource != null) && (dataSource instanceof 
Image)) {
 
 1321                     Image image = (Image) dataSource;
 
 1322                     timezones.add(TimeZone.getTimeZone(image.
getTimeZone()));
 
 1326             logger.log(Level.SEVERE, 
"Error getting data source time zones", ex); 
 
 1339         getCaseMetadata().setTextIndexName(textIndexName);
 
 1358         if (!hasDataSources) {
 
 1362                 logger.log(Level.SEVERE, 
"Error accessing case database", ex); 
 
 1467         String normalizedLocalPath;
 
 1469             normalizedLocalPath = Paths.get(localPath).normalize().toString();
 
 1470         } 
catch (InvalidPathException ex) {
 
 1471             String errorMsg = 
"Invalid local path provided: " + localPath; 
 
 1474         Report report = this.caseDb.addReport(normalizedLocalPath, srcModuleName, reportName);
 
 1487         return this.caseDb.getAllReports();
 
 1499         for (
Report report : reports) {
 
 1500             this.caseDb.deleteReport(report);
 
 1522     void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) 
throws CaseActionException {
 
 1524             caseMetadata.setCaseDisplayName(newCaseName);
 
 1525             eventPublisher.
publish(
new AutopsyEvent(Events.NAME.toString(), oldCaseName, newCaseName));
 
 1526             SwingUtilities.invokeLater(() -> {
 
 1528                     RecentCases.getInstance().updateRecentCase(oldCaseName, oldPath, newCaseName, newPath);
 
 1531                 } 
catch (Exception ex) {
 
 1532                     Logger.getLogger(
Case.class
 
 1533                             .getName()).log(Level.SEVERE, 
"Error updating case name in UI", ex); 
 
 1536         } 
catch (CaseMetadataException ex) {
 
 1537             throw new CaseActionException(NbBundle.getMessage(
this.getClass(), 
"Case.updateCaseName.exception.msg"), ex);
 
 1565         "Case.progressIndicatorTitle.creatingCase=Creating Case",
 
 1566         "Case.progressIndicatorCancelButton.label=Cancel",
 
 1567         "Case.progressMessage.preparing=Preparing...",
 
 1568         "Case.progressMessage.openingCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>" 
 1570     private void create(CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner) 
throws CaseActionException {
 
 1580                     Bundle.Case_progressIndicatorTitle_creatingCase(),
 
 1581                     new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
 
 1582                     Bundle.Case_progressIndicatorCancelButton_label(),
 
 1587         progressIndicator.
start(Bundle.Case_progressMessage_preparing());
 
 1596         caseLockingExecutor = Executors.newSingleThreadExecutor();
 
 1597         Future<Void> future = caseLockingExecutor.submit(() -> {
 
 1598             if (CaseType.SINGLE_USER_CASE == caseType) {
 
 1599                 create(caseType, caseDir, caseDisplayName, caseNumber, examiner, progressIndicator);
 
 1606                 progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources());
 
 1607                 acquireSharedCaseDirLock(caseDir);
 
 1614                 try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseDir)) {
 
 1615                     assert (null != resourcesLock);
 
 1617                         create(caseType, caseDir, caseDisplayName, caseNumber, examiner, progressIndicator);
 
 1618                     } catch (CaseActionException ex) {
 
 1623                         if (CaseType.MULTI_USER_CASE == caseType) {
 
 1624                             releaseSharedCaseDirLock(caseDir);
 
 1639             listener.setCaseActionFuture(future);
 
 1648         } 
catch (InterruptedException ex) {
 
 1649             throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getMessage()), ex);
 
 1650         } 
catch (ExecutionException ex) {
 
 1651             throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getCause().getMessage()), ex);
 
 1652         } 
catch (CancellationException ex) {
 
 1653             throw new CaseActionException(Bundle.Case_exceptionMessage_cancelled(), ex);
 
 1655             if (RuntimeProperties.runningWithGUI()) {
 
 1656                 SwingUtilities.invokeLater(() -> ((ModalDialogProgressIndicator) progressIndicator).setVisible(
false));
 
 1683         "Case.exceptionMessage.emptyCaseName=Case name is empty.",
 
 1684         "Case.progressMessage.creatingCaseDirectory=Creating case directory...",
 
 1685         "Case.progressMessage.creatingCaseDatabase=Creating case database...",
 
 1686         "Case.exceptionMessage.couldNotCreateCaseDatabaseName=Failed to create case database name from case name.",
 
 1687         "Case.progressMessage.creatingCaseMetadataFile=Creating case metadata file...",
 
 1688         "Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file.",
 
 1689         "Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database." 
 1695         if (caseDisplayName.isEmpty()) {
 
 1698         String caseName = displayNameToUniqueName(caseDisplayName);
 
 1720         progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
 
 1721         if (
new File(caseDir).exists() == 
false) {
 
 1722             Case.createCaseDirectory(caseDir, caseType);
 
 1728         progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDatabase());
 
 1729         String dbName = null;
 
 1731             if (CaseType.SINGLE_USER_CASE == caseType) {
 
 1737                 dbName = SINGLE_USER_CASE_DB_NAME;
 
 1739             } 
else if (CaseType.MULTI_USER_CASE == caseType) {
 
 1749             throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(), ex);
 
 1757         progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseMetadataFile());
 
 1759             this.caseMetadata = 
new CaseMetadata(caseDir, caseType, caseName, caseDisplayName, caseNumber, examiner, dbName);
 
 1761             throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateMetadataFile(), ex);
 
 1764         openServices(progressIndicator);
 
 1784             throw new CaseActionException(Bundle.Case_openException_couldNotOpenCase(Bundle.Case_exceptionMessage_failedToReadMetadata()), ex);
 
 1796                     Bundle.Case_progressIndicatorTitle_openingCase(),
 
 1797                     new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
 
 1798                     Bundle.Case_progressIndicatorCancelButton_label(),
 
 1803         progressIndicator.
start(Bundle.Case_progressMessage_preparing());
 
 1812         CaseType caseType = caseMetadata.getCaseType();
 
 1813         String caseName = caseMetadata.getCaseName();
 
 1814         progressIndicator.
start(Bundle.Case_progressMessage_preparing());
 
 1815         caseLockingExecutor = Executors.newSingleThreadExecutor();
 
 1816         Future<Void> future = caseLockingExecutor.submit(() -> {
 
 1817             if (CaseType.SINGLE_USER_CASE == caseType) {
 
 1818                 openCaseDatabase(progressIndicator);
 
 1819                 openServices(progressIndicator);
 
 1826                 progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources());
 
 1827                 acquireSharedCaseDirLock(caseMetadata.getCaseDirectory());
 
 1833                 try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseMetadata.getCaseDirectory())) {
 
 1834                     assert (null != resourcesLock);
 
 1836                         openCaseDatabase(progressIndicator);
 
 1837                         openServices(progressIndicator);
 
 1838                     } catch (CaseActionException ex) {
 
 1843                         if (CaseType.MULTI_USER_CASE == caseType) {
 
 1844                             releaseSharedCaseDirLock(caseName);
 
 1859             listener.setCaseActionFuture(future);
 
 1869         } 
catch (InterruptedException ex) {
 
 1870             throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getMessage()), ex);
 
 1871         } 
catch (ExecutionException ex) {
 
 1872             throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getCause().getMessage()), ex);
 
 1873         } 
catch (CancellationException ex) {
 
 1874             throw new CaseActionException(Bundle.Case_exceptionMessage_cancelled(), ex);
 
 1876             if (RuntimeProperties.runningWithGUI()) {
 
 1877                 SwingUtilities.invokeLater(() -> ((ModalDialogProgressIndicator) progressIndicator).setVisible(
false));
 
 1893         "Case.progressMessage.openingCaseDatabase=Opening case database...",
 
 1894         "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database." 
 1901             progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseDatabase());
 
 1902             if (CaseType.SINGLE_USER_CASE == caseMetadata.getCaseType()) {
 
 1903                 this.caseDb = 
SleuthkitCase.
openCase(Paths.get(caseMetadata.getCaseDirectory(), caseMetadata.getCaseDatabaseName()).toString());
 
 1913                 throw new CaseActionException(NbBundle.getMessage(
Case.class, 
"Case.open.exception.multiUserCaseNotEnabled"));
 
 1916             throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(), ex);
 
 1929         "Case.progressMessage.switchingLogDirectory=Switching log directory...",
 
 1930         "Case.progressMessage.settingUpTskErrorReporting=Setting up SleuthKit error reporting...",
 
 1931         "Case.progressMessage.openingCaseLevelServices=Opening case-level services...",
 
 1932         "Case.progressMessage.openingApplicationServiceResources=Opening application service case resources...",
 
 1933         "Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
 
 1939         progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
 
 1945         progressIndicator.
progress(Bundle.Case_progressMessage_settingUpTskErrorReporting());
 
 1946         this.sleuthkitErrorReporter = 
new SleuthkitErrorReporter(MIN_SECS_BETWEEN_TSK_ERROR_REPORTS, NbBundle.getMessage(
Case.class, 
"IntervalErrorReport.ErrorText"));
 
 1947         this.caseDb.addErrorObserver(this.sleuthkitErrorReporter);
 
 1952         progressIndicator.
progress(Bundle.Case_progressMessage_clearingTempDirectory());
 
 1958         progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseLevelServices());
 
 1959         this.caseServices = 
new Services(this.caseDb);
 
 1965         progressIndicator.
progress(Bundle.Case_progressMessage_openingApplicationServiceResources());
 
 1966         openAppServiceCaseResources();
 
 1972         if (CaseType.MULTI_USER_CASE == 
this.caseMetadata.getCaseType()) {
 
 1973             progressIndicator.
progress(Bundle.Case_progressMessage_settingUpNetworkCommunications());
 
 1976                 collaborationMonitor = 
new CollaborationMonitor(this.getName());
 
 1983                 logger.log(Level.SEVERE, 
"Failed to setup network communications", ex); 
 
 1986                     SwingUtilities.invokeLater(() -> 
MessageNotifyUtil.
Notify.
error(NbBundle.getMessage(
Case.class, 
"Case.CollaborationSetup.FailNotify.Title"), NbBundle.getMessage(
Case.class, 
"Case.CollaborationSetup.FailNotify.ErrMsg")));
 
 1998     @NbBundle.Messages({
 
 1999         "# {0} - service name", 
"Case.serviceOpenCaseResourcesProgressIndicator.title={0} Opening Case Resources",
 
 2000         "# {0} - service name", 
"Case.servicesException.notificationTitle={0} Error",
 
 2001         "# {0} - service name", 
"Case.servicesException.serviceResourcesOpenCancelled=Opening case resources for {0} cancelled",
 
 2002         "# {0} - service name", 
"# {1} - exception message", 
"Case.servicesException.serviceResourcesOpenError=Could not open case resources for {0} service: {1}" 
 2009         ExecutorService executor = Executors.newSingleThreadExecutor();
 
 2017                         Bundle.Case_serviceOpenCaseResourcesProgressIndicator_title(service.getServiceName()),
 
 2018                         new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
 
 2019                         Bundle.Case_progressIndicatorCancelButton_label(),
 
 2024             progressIndicator.
start(Bundle.Case_progressMessage_preparing());
 
 2030             Future<Void> future = executor.submit(() -> {
 
 2031                 service.openCaseResources(context);
 
 2040             } 
catch (InterruptedException ex) {
 
 2041                 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to open case resources", service.getServiceName()), ex);
 
 2043             } 
catch (CancellationException ex) {
 
 2049                 Case.
logger.log(Level.WARNING, String.format(
"%s service opening of case resources cancelled", service.getServiceName()));
 
 2052                             Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
 
 2053                             Bundle.Case_servicesException_serviceResourcesOpenCancelled(service.getServiceName())));
 
 2055             } 
catch (ExecutionException ex) {
 
 2061                 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
 
 2064                             Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
 
 2065                             Bundle.Case_servicesException_serviceResourcesOpenError(service.getServiceName(), ex.getLocalizedMessage())));
 
 2076         executor.shutdown();
 
 2085         "Case.progressMessage.closingCaseResources=<html>Preparing to close case resources.<br>This may take time if another user is upgrading the case.</html>",
 
 2086         "Case.progressMessage.notifyingCaseEventSubscribers=Notifying case event subscribers...",
 
 2087         "Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
 
 2088         "Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
 
 2089         "Case.progressMessage.closingApplicationServiceResources=Closing case-specific application service resources...",
 
 2090         "Case.progressMessage.tearingDownNetworkCommunications=Tearing down network communications...",
 
 2091         "Case.progressMessage.closingCaseDatabase=Closing case database...",
 
 2092         "Case.progressMessage.tearingDownTskErrorReporting=Tearing down SleuthKit error reporting..." 
 2103                     Bundle.Case_progressIndicatorTitle_closingCase());
 
 2107         progressIndicator.
start(Bundle.Case_progressMessage_preparing());
 
 2116         Future<Void> future = caseLockingExecutor.submit(() -> {
 
 2117             if (CaseType.SINGLE_USER_CASE == caseMetadata.getCaseType()) {
 
 2118                 close(progressIndicator);
 
 2120                 String caseName = caseMetadata.getCaseName();
 
 2126                 progressIndicator.
start(Bundle.Case_progressMessage_closingCaseResources());
 
 2127                 try (
CoordinationService.
Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseMetadata.getCaseDirectory())) {
 
 2128                     assert (null != resourcesLock);
 
 2129                     close(progressIndicator);
 
 2135                     releaseSharedCaseDirLock(caseName);
 
 2151             logger.log(Level.INFO, 
"Closing case with metadata file path {0}", getCaseMetadata().getFilePath()); 
 
 2153         } 
catch (InterruptedException ex) {
 
 2154             throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getMessage()), ex);
 
 2155         } 
catch (ExecutionException ex) {
 
 2156             throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getCause().getMessage()), ex);
 
 2157         } 
catch (CancellationException ex) {
 
 2160             caseLockingExecutor.shutdown();
 
 2174         if (CaseType.MULTI_USER_CASE == caseMetadata.getCaseType()) {
 
 2175             progressIndicator.
progress(Bundle.Case_progressMessage_tearingDownNetworkCommunications());
 
 2176             if (null != collaborationMonitor) {
 
 2177                 collaborationMonitor.shutdown();
 
 2186         progressIndicator.
progress(Bundle.Case_progressMessage_closingApplicationServiceResources());
 
 2187         closeAppServiceCaseResources();
 
 2192         progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseLevelServices());
 
 2194             this.caseServices.close();
 
 2195         } 
catch (IOException ex) {
 
 2196             logger.log(Level.SEVERE, String.format(
"Error closing internal case services for %s at %s", 
this.getName(), this.getCaseDirectory()), ex);
 
 2202         progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseDatabase());
 
 2208         progressIndicator.
progress(Bundle.Case_progressMessage_tearingDownTskErrorReporting());
 
 2209         caseDb.removeErrorObserver(sleuthkitErrorReporter);
 
 2214         progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
 
 2223         "# {0} - serviceName", 
"Case.serviceCloseResourcesProgressIndicator.title={0} Closing Case Resources",
 
 2224         "# {0} - service name", 
"# {1} - exception message", 
"Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1}" 
 2231         ExecutorService executor = Executors.newSingleThreadExecutor();
 
 2239                         Bundle.Case_serviceCloseResourcesProgressIndicator_title(service.getServiceName()));
 
 2243             progressIndicator.
start(Bundle.Case_progressMessage_preparing());
 
 2246             Future<Void> future = executor.submit(() -> {
 
 2247                 service.closeCaseResources(context);
 
 2255             } 
catch (InterruptedException ex) {
 
 2256                 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to close case resources", service.getServiceName()), ex);
 
 2258             } 
catch (CancellationException ex) {
 
 2259                 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected cancellation while waiting on %s service to close case resources", service.getServiceName()), ex);
 
 2261             } 
catch (ExecutionException ex) {
 
 2262                 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
 
 2265                             Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
 
 2266                             Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
 
 2277         executor.shutdown();
 
 2288     @Messages({
"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
 
 2292             if (null == caseDirLock) {
 
 2296             throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
 
 2306         if (caseDirLock != null) {
 
 2308                 caseDirLock.release();
 
 2311                 logger.log(Level.SEVERE, String.format(
"Failed to release shared case directory lock for %s", caseDir), ex);
 
 2323         File subDirectory = Paths.get(getOutputDirectory(), subDirectoryName).toFile();
 
 2324         if (!subDirectory.exists()) {
 
 2325             subDirectory.mkdirs();
 
 2327         return subDirectory.toString();
 
 2337             this.caseActionFuture = caseActionFuture;
 
 2341             this.caseContext = caseContext;
 
 2346             if (null != this.caseContext) {
 
 2349             if (null != this.caseActionFuture) {
 
 2350                 this.caseActionFuture.cancel(
true);
 
 2377         createAsCurrentCase(caseDir, caseDisplayName, caseNumber, examiner, CaseType.SINGLE_USER_CASE);
 
 2401     public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType) 
throws CaseActionException {
 
 2402         createAsCurrentCase(caseDir, caseDisplayName, caseNumber, examiner, caseType);
 
 2418         openAsCurrentCase(caseMetadataFilePath);
 
 2474         return new File(filePath).isFile();
 
 2499         return isCaseOpen();
 
 2513         return "ModuleOutput"; 
 
 2526     public static PropertyChangeSupport
 
 2528         return new PropertyChangeSupport(
Case.class
 
 2542         return getModuleDirectory();
 
 2562             Image newDataSource = caseDb.getImageById(imgId);
 
 2563             notifyDataSourceAdded(newDataSource, UUID.randomUUID());
 
 2564             return newDataSource;
 
 2566             throw new CaseActionException(NbBundle.getMessage(
this.getClass(), 
"Case.addImg.exception.msg"), ex);
 
 2579         return getTimeZones();
 
 2594         deleteReports(reports);
 
String getLogDirectoryPath()
 
static final AutopsyEventPublisher eventPublisher
 
List< Content > getDataSources()
 
String getModuleOutputDirectoryRelativePath()
 
void notifyContentTagDeleted(ContentTag deletedTag)
 
static final int MIN_SECS_BETWEEN_TSK_ERROR_REPORTS
 
static CaseType fromString(String typeName)
 
ExecutorService caseLockingExecutor
 
void publishLocally(AutopsyEvent event)
 
void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag)
 
Set< TimeZone > getTimeZones()
 
Image addImage(String imgPath, long imgId, String timeZone)
 
static synchronized IngestManager getInstance()
 
static CoordinationService.Lock acquireExclusiveCaseResourcesLock(String caseDir)
 
static boolean runningWithGUI
 
static void closeCurrentCase()
 
String getTempDirectory()
 
void cancelAllIngestJobs()
 
static boolean existsCurrentCase()
 
static void removePropertyChangeListener(PropertyChangeListener listener)
 
static final Logger logger
 
void publish(AutopsyEvent event)
 
void create(CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner)
 
static final int RESOURCES_LOCK_TIMOUT_HOURS
 
String getLocalizedDisplayName()
 
void progress(String message)
 
ADDING_DATA_SOURCE_FAILED
 
static final String EXPORT_FOLDER
 
String getCaseDirectory()
 
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)
 
static void addCaseNameToMainWindowTitle(String caseName)
 
static final String CACHE_FOLDER
 
static String getAutopsyVersion()
 
CaseType(String typeName)
 
String getReportDirectory()
 
static boolean getIsMultiUserModeEnabled()
 
void addReport(String localPath, String srcModuleName, String reportName)
 
static void updateGUIForCaseOpened(Case newCurrentCase)
 
static CaseDbConnectionInfo getDatabaseConnectionInfo()
 
String getModulesOutputDirAbsPath()
 
static void cleanupDeletedCase(CaseMetadata metadata, ProgressIndicator progressIndicator)
 
static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType)
 
void closeAppServiceCaseResources()
 
void setTextIndexName(String textIndexName)
 
static final String SINGLE_USER_CASE_DB_NAME
 
static void deleteCase(CaseMetadata metadata)
 
void deleteReports(Collection<?extends Report > reports, boolean deleteFromDisk)
 
List< Report > getAllReports()
 
static void clearTempSubDir(String tempSubDirPath)
 
static boolean isValidName(String caseName)
 
void create(CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner, ProgressIndicator progressIndicator)
 
void acquireSharedCaseDirLock(String caseDir)
 
CollaborationMonitor collaborationMonitor
 
void releaseSharedCaseDirLock(String caseDir)
 
static void closeCoreWindows()
 
static String getModulesOutputDirRelPath()
 
void start(String message, int totalWorkUnits)
 
Set< TimeZone > getTimeZone()
 
static final String MODULE_FOLDER
 
static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
 
void openCaseDatabase(ProgressIndicator progressIndicator)
 
void openAppServiceCaseResources()
 
void openServices(ProgressIndicator progressIndicator)
 
static void invokeStartupDialog()
 
void openRemoteEventChannel(String channelName)
 
static String displayNameToUniqueName(String caseDisplayName)
 
static void openAsCurrentCase(String caseMetadataFilePath)
 
static void removeEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
 
Lock tryGetExclusiveLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
 
static void getMainWindowAndAppName()
 
static final int DIR_LOCK_TIMOUT_HOURS
 
void close(ProgressIndicator progressIndicator)
 
CaseMetadata caseMetadata
 
SleuthkitCase getSleuthkitCase()
 
void closeRemoteEventChannel()
 
void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag)
 
static PropertyChangeSupport getPropertyChangeSupport()
 
String getCacheDirectory()
 
static void addPropertyChangeListener(PropertyChangeListener listener)
 
void removeSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
 
String getModuleDirectory()
 
static void removeEventSubscriber(String eventName, PropertyChangeListener subscriber)
 
void deleteReports(Collection<?extends Report > reports)
 
void notifyDataSourceAdded(Content dataSource, UUID addingDataSourceEventId)
 
static boolean pathExists(String filePath)
 
SleuthkitErrorReporter sleuthkitErrorReporter
 
BLACKBOARD_ARTIFACT_TAG_ADDED
 
static void open(String caseMetadataFilePath)
 
static final Object currentCaseWriteLock
 
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)
 
void open(Path caseMetadataFilePath)
 
static SleuthkitCase openCase(String dbPath)
 
static String convertToAlphaNumericFormat(String timeZoneId)
 
static final String LOG_FOLDER
 
static SleuthkitCase newCase(String dbPath)
 
String getBackupDatabasePath()
 
Lock tryGetSharedLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
 
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)
 
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 void warn(String title, String message)
 
static boolean isCaseOpen()
 
String getTextIndexName()
 
static final String REPORTS_FOLDER
 
static final String TEMP_FOLDER
 
BLACKBOARD_ARTIFACT_TAG_DELETED
 
static void addEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)