19 package org.sleuthkit.autopsy.casemodule;
21 import java.awt.Frame;
22 import java.beans.PropertyChangeListener;
23 import java.beans.PropertyChangeSupport;
24 import java.io.BufferedInputStream;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.text.DateFormat;
29 import java.text.SimpleDateFormat;
30 import java.util.GregorianCalendar;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.List;
36 import java.util.TimeZone;
37 import java.util.logging.Level;
38 import javax.swing.JOptionPane;
39 import javax.swing.SwingUtilities;
40 import org.openide.util.Lookup;
41 import org.openide.util.NbBundle;
42 import org.openide.util.actions.CallableSystemAction;
43 import org.openide.util.actions.SystemAction;
44 import org.openide.windows.WindowManager;
60 @SuppressWarnings(
"deprecation")
64 private static String appName = null;
70 public static final String propStartup =
"LBL_StartupDialog";
72 private static final PropertyChangeSupport pcs =
new PropertyChangeSupport(
Case.class);
136 private final XMLCaseManagement
xmlcm;
139 private static Case currentCase = null;
142 static final String CASE_EXTENSION =
"aut";
143 static final String CASE_DOT_EXTENSION =
"." + CASE_EXTENSION;
146 private boolean hasData =
false;
151 private Case(String name, String number, String examiner, String configFilePath, XMLCaseManagement xmlcm,
SleuthkitCase db) {
153 this.number = number;
154 this.examiner = examiner;
155 this.configFilePath = configFilePath;
177 if (currentCase != null) {
180 throw new IllegalStateException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"));
190 return currentCase != null;
205 if (oldCase != null) {
210 }
catch (Exception e) {
211 logger.log(Level.SEVERE,
"Case listener threw exception", e);
213 NbBundle.getMessage(
Case.class,
214 "Case.changeCase.errListenToCaseUpdates.msg"),
217 doCaseNameChange(
"");
221 }
catch (Exception e) {
222 logger.log(Level.SEVERE,
"Case listener threw exception", e);
224 NbBundle.getMessage(
Case.class,
225 "Case.changeCase.errListenToCaseUpdates.msg"),
230 if (newCase != null) {
231 currentCase = newCase;
237 }
catch (Exception e) {
238 logger.log(Level.SEVERE,
"Case listener threw exception", e);
240 NbBundle.getMessage(
Case.class,
241 "Case.changeCase.errListenToCaseUpdates.msg"),
244 doCaseChange(currentCase);
247 pcs.firePropertyChange(
Events.
NAME.toString(),
"", currentCase.
name);
248 }
catch (Exception e) {
249 logger.log(Level.SEVERE,
"Case threw exception", e);
251 NbBundle.getMessage(
Case.class,
252 "Case.changeCase.errListenToCaseUpdates.msg"),
255 doCaseNameChange(currentCase.
name);
257 RecentCases.getInstance().addRecentCase(currentCase.
name, currentCase.
configFilePath);
263 AddImageProcess makeAddImageProcess(String timezone,
boolean processUnallocSpace,
boolean noFatOrphans) {
278 logger.log(Level.INFO,
"Creating new case.\ncaseDir: {0}\ncaseName: {1}",
new Object[]{caseDir, caseName});
281 if (
new File(caseDir).exists() ==
false) {
282 Case.createCaseDirectory(caseDir);
285 String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION;
287 XMLCaseManagement xmlcm =
new XMLCaseManagement();
288 xmlcm.create(caseDir, caseName, examiner, caseNumber);
291 String dbPath = caseDir + File.separator +
"autopsy.db";
296 logger.log(Level.SEVERE,
"Error creating a case: " + caseName +
" in dir " + caseDir, ex);
298 NbBundle.getMessage(
Case.class,
"Case.create.exception.msg", caseName, caseDir), ex);
305 Case newCase =
new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db);
319 logger.log(Level.INFO,
"Opening case.\nconfigFilePath: {0}", configFilePath);
322 XMLCaseManagement xmlcm =
new XMLCaseManagement();
324 xmlcm.open(configFilePath);
327 String caseName = xmlcm.getCaseName();
328 String caseNumber = xmlcm.getCaseNumber();
329 String examiner = xmlcm.getCaseExaminer();
331 if (caseName.equals(
"")) {
335 String caseDir = xmlcm.getCaseDirectory();
336 String dbPath = caseDir + File.separator +
"autopsy.db";
339 JOptionPane.showMessageDialog(null,
340 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.msg",
342 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.title"),
343 JOptionPane.INFORMATION_MESSAGE);
346 checkImagesExist(db);
352 Case openedCase =
new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db);
355 changeCase(openedCase);
357 }
catch (Exception ex) {
358 logger.log(Level.SEVERE,
"Error opening the case: ", ex);
360 CaseCloseAction closeCase = SystemAction.get(CaseCloseAction.class);
361 closeCase.actionPerformed(null);
362 if (!configFilePath.endsWith(CASE_DOT_EXTENSION)) {
364 NbBundle.getMessage(
Case.class,
"Case.open.exception.checkFile.msg", CASE_DOT_EXTENSION), ex);
366 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.open.exception.gen.msg") +
". " + ex.getMessage(), ex);
372 Map<Long, String> imgPaths =
new HashMap<>();
375 for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
376 if (entry.getValue().size() > 0) {
377 imgPaths.put(entry.getKey(), entry.getValue().get(0));
381 logger.log(Level.WARNING,
"Error getting image paths", ex);
390 Map<Long, String> imgPaths = getImagePaths(db);
391 for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
392 long obj_id = entry.getKey();
393 String path = entry.getValue();
394 boolean fileExists = (pathExists(path)
395 || driveExists(path));
397 int ret = JOptionPane.showConfirmDialog(null,
398 NbBundle.getMessage(
Case.class,
399 "Case.checkImgExist.confDlg.doesntExist.msg",
401 NbBundle.getMessage(
Case.class,
402 "Case.checkImgExist.confDlg.doesntExist.title"),
403 JOptionPane.YES_NO_OPTION);
404 if (ret == JOptionPane.YES_OPTION) {
406 MissingImageDialog.makeDialog(obj_id, db);
409 logger.log(Level.WARNING,
"Selected image files don't match old files!");
426 logger.log(Level.INFO,
"Adding image to Case. imgPath: {0} ID: {1} TimeZone: {2}",
new Object[]{imgPath, imgId, timeZone});
433 }
catch (Exception e) {
434 logger.log(Level.SEVERE,
"Case listener threw exception", e);
436 NbBundle.getMessage(
this.getClass(),
437 "Case.changeCase.errListenToCaseUpdates.msg"),
442 }
catch (Exception ex) {
443 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.addImg.exception.msg"), ex);
454 void addLocalDataSource(
Content newDataSource) {
456 notifyNewDataSource(newDataSource);
465 void notifyNewDataSource(
Content newDataSource) {
468 pcs.firePropertyChange(Events.DATA_SOURCE_ADDED.toString(), null, newDataSource);
469 }
catch (Exception e) {
470 logger.log(Level.SEVERE,
"Case threw exception", e);
471 MessageNotifyUtil.Notify.show(NbBundle.getMessage(
this.getClass(),
"Case.moduleErr"),
472 NbBundle.getMessage(
this.getClass(),
473 "Case.changeCase.errListenToCaseUpdates.msg"),
474 MessageNotifyUtil.MessageType.ERROR);
476 CoreComponentControl.openCoreWindows();
506 }
catch (Exception e) {
507 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.closeCase.exception.msg"), e);
519 logger.log(Level.INFO,
"Deleting case.\ncaseDir: {0}", caseDir);
524 boolean result = deleteCaseDirectory(caseDir);
526 RecentCases.getInstance().removeRecentCase(this.name, this.configFilePath);
528 if (result ==
false) {
530 NbBundle.getMessage(
this.getClass(),
"Case.deleteCase.exception.msg", caseDir));
532 }
catch (Exception ex) {
533 logger.log(Level.SEVERE,
"Error deleting the current case dir: " + caseDir, ex);
534 throw new CaseActionException(
535 NbBundle.getMessage(
this.getClass(),
"Case.deleteCase.exception.msg2", caseDir), ex);
547 void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath)
throws CaseActionException {
549 xmlcm.setCaseName(newCaseName);
551 RecentCases.getInstance().updateRecentCase(oldCaseName, oldPath, newCaseName, newPath);
553 pcs.firePropertyChange(Events.NAME.toString(), oldCaseName, newCaseName);
554 }
catch (Exception e) {
555 logger.log(Level.SEVERE,
"Case listener threw exception", e);
556 MessageNotifyUtil.Notify.show(NbBundle.getMessage(
this.getClass(),
"Case.moduleErr"),
557 NbBundle.getMessage(
this.getClass(),
558 "Case.changeCase.errListenToCaseUpdates.msg"),
559 MessageNotifyUtil.MessageType.ERROR);
561 doCaseNameChange(newCaseName);
563 }
catch (Exception e) {
564 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.updateCaseName.exception.msg"), e);
574 void updateExaminer(String oldExaminer, String newExaminer)
throws CaseActionException {
576 xmlcm.setCaseExaminer(newExaminer);
577 examiner = newExaminer;
579 pcs.firePropertyChange(Events.EXAMINER.toString(), oldExaminer, newExaminer);
580 }
catch (Exception e) {
581 logger.log(Level.SEVERE,
"Case listener threw exception", e);
582 MessageNotifyUtil.Notify.show(NbBundle.getMessage(
this.getClass(),
"Case.moduleErr"),
583 NbBundle.getMessage(
this.getClass(),
584 "Case.changeCase.errListenToCaseUpdates.msg"),
585 MessageNotifyUtil.MessageType.ERROR);
587 }
catch (Exception e) {
588 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.updateExaminer.exception.msg"), e);
598 void updateCaseNumber(String oldCaseNumber, String newCaseNumber)
throws CaseActionException {
600 xmlcm.setCaseNumber(newCaseNumber);
601 number = newCaseNumber;
604 pcs.firePropertyChange(Events.NUMBER.toString(), oldCaseNumber, newCaseNumber);
605 }
catch (Exception e) {
606 logger.log(Level.SEVERE,
"Case listener threw exception", e);
607 MessageNotifyUtil.Notify.show(NbBundle.getMessage(
this.getClass(),
"Case.moduleErr"),
608 NbBundle.getMessage(
this.getClass(),
609 "Case.changeCase.errListenToCaseUpdates.msg"),
610 MessageNotifyUtil.MessageType.ERROR);
612 }
catch (Exception e) {
613 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.updateCaseNum.exception.msg"), e);
623 return currentCase != null;
632 configFilePath = givenPath;
640 String getConfigFilePath() {
641 return configFilePath;
659 if ((appName == null) || appName.equals(
"")) {
660 appName = WindowManager.getDefault().getMainWindow().getTitle();
701 return xmlcm.getCaseDirectory();
714 return xmlcm.getTempDir();
727 return xmlcm.getCacheDir();
740 return xmlcm.getExportDir();
753 return xmlcm.getLogDir();
766 return xmlcm.getCreatedDate();
777 return this.getCaseDirectory() + File.separator + getModulesOutputDirRelPath();
788 return "ModuleOutput";
808 hasData = (list.size() > 0);
818 Set<TimeZone> timezones =
new HashSet<>();
820 for (
Content c : getDataSources()) {
822 if ((dataSource != null) && (dataSource instanceof
Image)) {
823 Image image = (Image) dataSource;
824 timezones.add(TimeZone.getTimeZone(image.
getTimeZone()));
828 logger.log(Level.INFO,
"Error getting time zones", ex);
834 pcs.addPropertyChangeListener(listener);
838 pcs.removePropertyChangeListener(listener);
849 return new File(imgPath).isFile();
854 private static final String pdisk =
"\\\\.\\physicaldrive";
855 private static final String dev =
"/dev/";
857 static boolean isPhysicalDrive(String path) {
858 return path.toLowerCase().startsWith(pdisk)
859 || path.toLowerCase().startsWith(dev);
865 static boolean isPartition(String path) {
866 return path.toLowerCase().startsWith(
"\\\\.\\")
867 && path.toLowerCase().endsWith(
":");
877 static boolean driveExists(String path) {
879 BufferedInputStream br = null;
882 br =
new BufferedInputStream(
new FileInputStream(tmp));
885 }
catch (Exception ex) {
892 }
catch (IOException ex) {
908 TimeZone zone = TimeZone.getTimeZone(timezoneID);
909 int offset = zone.getRawOffset() / 1000;
910 int hour = offset / 3600;
911 int min = (offset % 3600) / 60;
913 DateFormat dfm =
new SimpleDateFormat(
"z");
914 dfm.setTimeZone(zone);
915 boolean hasDaylight = zone.useDaylightTime();
916 String first = dfm.format(
new GregorianCalendar(2010, 1, 1).getTime()).substring(0, 3);
917 String second = dfm.format(
new GregorianCalendar(2011, 6, 6).getTime()).substring(0, 3);
919 String result = first + Integer.toString(mid);
921 result = result +
":" + Integer.toString(min);
924 result = result + second;
943 static void createCaseDirectory(String caseDir, String caseName)
throws CaseActionException {
944 createCaseDirectory(caseDir);
955 static void createCaseDirectory(String caseDir)
throws CaseActionException {
960 throw new CaseActionException(
961 NbBundle.getMessage(Case.class,
"Case.createCaseDir.exception.existNotDir", caseDir));
962 }
else if (!caseDirF.
canRead() || !caseDirF.canWrite()) {
963 throw new CaseActionException(
964 NbBundle.getMessage(Case.class,
"Case.createCaseDir.exception.existCantRW", caseDir));
969 boolean result = (caseDirF).mkdirs();
970 if (result ==
false) {
971 throw new CaseActionException(
972 NbBundle.getMessage(Case.class,
"Case.createCaseDir.exception.cantCreate", caseDir));
976 result = result && (
new File(caseDir +
File.separator + XMLCaseManagement.EXPORT_FOLDER_RELPATH)).mkdir()
977 && (
new File(caseDir +
File.separator + XMLCaseManagement.LOG_FOLDER_RELPATH)).mkdir()
978 && (
new File(caseDir +
File.separator + XMLCaseManagement.TEMP_FOLDER_RELPATH)).mkdir()
979 && (
new File(caseDir +
File.separator + XMLCaseManagement.CACHE_FOLDER_RELPATH)).mkdir();
981 if (result ==
false) {
982 throw new CaseActionException(
983 NbBundle.getMessage(Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", caseDir));
986 final String modulesOutDir = caseDir +
File.separator + getModulesOutputDirRelPath();
987 result =
new File(modulesOutDir).mkdir();
988 if (result ==
false) {
989 throw new CaseActionException(
990 NbBundle.getMessage(Case.class,
"Case.createCaseDir.exception.cantCreateModDir",
994 }
catch (Exception e) {
995 throw new CaseActionException(
996 NbBundle.getMessage(Case.class,
"Case.createCaseDir.exception.gen", caseDir), e);
1007 static boolean deleteCaseDirectory(
File casePath) {
1008 logger.log(Level.INFO,
"Deleting case directory: {0}", casePath.getAbsolutePath());
1009 return FileUtil.deleteDir(casePath);
1024 SwingUtilities.invokeLater(
new Runnable() {
1041 return !(caseName.contains(
"\\") || caseName.contains(
"/") || caseName.contains(
":")
1042 || caseName.contains(
"*") || caseName.contains(
"?") || caseName.contains(
"\"")
1043 || caseName.contains(
"<") || caseName.contains(
">") || caseName.contains(
"|"));
1048 if (tempFolder.isDirectory()) {
1049 File[] files = tempFolder.listFiles();
1050 if (files.length > 0) {
1051 for (File file : files) {
1052 if (file.isDirectory()) {
1053 deleteCaseDirectory(file);
1069 File modulesOutputDirF =
new File(modulesOutputDir);
1070 if (!modulesOutputDirF.exists()) {
1071 logger.log(Level.INFO,
"Creating modules output dir for the case.");
1074 if (!modulesOutputDirF.mkdir()) {
1075 logger.log(Level.SEVERE,
"Error creating modules output dir for the case, dir: {0}", modulesOutputDir);
1077 }
catch (SecurityException e) {
1078 logger.log(Level.SEVERE,
"Error creating modules output dir for the case, dir: " + modulesOutputDir, e);
1085 logger.log(Level.INFO,
"Changing Case to: {0}", toChangeTo);
1086 if (toChangeTo != null) {
1090 checkSubFolders(toChangeTo);
1094 CallableSystemAction.get(CaseCloseAction.class).setEnabled(
true);
1095 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
true);
1096 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
true);
1110 CallableSystemAction.get(
AddImageAction.class).setEnabled(
false);
1111 CallableSystemAction.get(CaseCloseAction.class).setEnabled(
false);
1112 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
false);
1113 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
false);
1118 Frame f = WindowManager.getDefault().getMainWindow();
1134 if (!newCaseName.equals(
"")) {
1135 Frame f = WindowManager.getDefault().getMainWindow();
1166 Report report = this.db.
addReport(localPath, srcModuleName, reportName);
1169 }
catch (Exception ex) {
1170 String errorMessage = String.format(
"A Case %s listener threw an exception",
Events.
REPORT_ADDED.toString());
1171 logger.log(Level.SEVERE, errorMessage, ex);
1188 hasData = (getDataSources().size() > 0);
String getLogDirectoryPath()
List< Content > getDataSources()
List< Report > getAllReports()
static String convertTimeZone(String timezoneID)
static final PropertyChangeSupport pcs
AddImageProcess makeAddImageProcess(String timezone, boolean processUnallocSpace, boolean noFatFsOrphans)
Case(String name, String number, String examiner, String configFilePath, XMLCaseManagement xmlcm, SleuthkitCase db)
Image addImage(String imgPath, long imgId, String timeZone)
void addErrorObserver(ErrorObserver observer)
String getTempDirectory()
static void doCaseNameChange(String newCaseName)
static boolean existsCurrentCase()
static void open(String configFilePath)
String getCaseDirectory()
static void openCoreWindows()
static String getAutopsyVersion()
static void setLogDirectory(String directoryPath)
void setConfigFilePath(String givenPath)
void addReport(String localPath, String srcModuleName, String reportName)
Map< Long, List< String > > getImagePaths()
String getModulesOutputDirAbsPath()
static void changeCase(Case newCase)
List< Report > getAllReports()
static boolean isValidName(String caseName)
static void closeCoreWindows()
static String getModulesOutputDirRelPath()
Image getImageById(long id)
Set< TimeZone > getTimeZone()
static void invokeStartupDialog()
void actionPerformed(ActionEvent e)
SleuthkitCase getSleuthkitCase()
static void checkSubFolders(Case openedCase)
static PropertyChangeSupport getPropertyChangeSupport()
Report addReport(String localPath, String sourceModuleName, String reportName)
String getCacheDirectory()
static void checkImagesExist(SleuthkitCase db)
List< Content > getRootObjects()
static synchronized void removePropertyChangeListener(PropertyChangeListener listener)
static boolean pathExists(String imgPath)
final XMLCaseManagement xmlcm
static void error(String title, String message)
static synchronized void addPropertyChangeListener(PropertyChangeListener listener)
static void create(String caseDir, String caseName, String caseNumber, String examiner)
static Case getCurrentCase()
static void show(String title, String message, MessageType type, ActionListener actionListener)
static SleuthkitCase openCase(String dbPath)
static void runAddImageAction()
static SleuthkitCase newCase(String dbPath)
String getBackupDatabasePath()
void receiveError(String context, String errorMessage)
static String getAppName()
static String getVersion()
String getExportDirectory()
static void clearTempFolder()
static StartupWindowProvider getInstance()
static boolean isCaseOpen()
static Logger getLogger(String name)
static void doCaseChange(Case toChangeTo)