Merge branch 'develop' of https://github.com/sleuthkit/autopsy into 2452-UpdateLocalDiskDSP
2
.gitignore
vendored
@ -77,3 +77,5 @@ Core/src/org/sleuthkit/autopsy/casemodule/docs/screenshot.png
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.*.swp
|
.*.swp
|
||||||
Core/src/org/sleuthkit/autopsy/datamodel/ranges.csv
|
Core/src/org/sleuthkit/autopsy/datamodel/ranges.csv
|
||||||
|
|
||||||
|
thunderbirdparser/release/modules/ext
|
||||||
|
@ -37,6 +37,7 @@ import javax.swing.JPanel;
|
|||||||
import javax.swing.JTextArea;
|
import javax.swing.JTextArea;
|
||||||
import javax.swing.JToggleButton;
|
import javax.swing.JToggleButton;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||||
import org.sleuthkit.autopsy.datasourceprocessors.RawDSProcessor;
|
import org.sleuthkit.autopsy.datasourceprocessors.RawDSProcessor;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -56,8 +57,11 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
AddImageWizardSelectDspVisual(String lastDspUsed) {
|
AddImageWizardSelectDspVisual(String lastDspUsed) {
|
||||||
initComponents();
|
initComponents();
|
||||||
selectedDsp = lastDspUsed;
|
selectedDsp = lastDspUsed;
|
||||||
|
//if the last selected DSP was the Local Disk DSP and it would be disabled then we want to select a different DSP
|
||||||
|
if ((Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) && selectedDsp.equals(LocalDiskDSProcessor.getType())) {
|
||||||
|
selectedDsp = ImageDSProcessor.getType();
|
||||||
|
}
|
||||||
createDataSourceProcessorButtons();
|
createDataSourceProcessorButtons();
|
||||||
|
|
||||||
//add actionlistner to listen for change
|
//add actionlistner to listen for change
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +91,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
return selectedDsp;
|
return selectedDsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages("AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode")
|
||||||
/**
|
/**
|
||||||
* Create the a button for each DataSourceProcessor that should exist as an
|
* Create the a button for each DataSourceProcessor that should exist as an
|
||||||
* option.
|
* option.
|
||||||
@ -110,6 +115,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
constraints.anchor = GridBagConstraints.LINE_START;
|
constraints.anchor = GridBagConstraints.LINE_START;
|
||||||
Dimension spacerBlockDimension = new Dimension(6, 4); // Space between left edge and button, Space between rows
|
Dimension spacerBlockDimension = new Dimension(6, 4); // Space between left edge and button, Space between rows
|
||||||
for (String dspType : dspList) {
|
for (String dspType : dspList) {
|
||||||
|
boolean shouldAddMultiUserWarning = false;
|
||||||
constraints.weightx = 1;
|
constraints.weightx = 1;
|
||||||
//Add a spacer
|
//Add a spacer
|
||||||
Filler spacer = new Filler(spacerBlockDimension, spacerBlockDimension, spacerBlockDimension);
|
Filler spacer = new Filler(spacerBlockDimension, spacerBlockDimension, spacerBlockDimension);
|
||||||
@ -120,6 +126,11 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
//Add the button
|
//Add the button
|
||||||
JToggleButton dspButton = createDspButton(dspType);
|
JToggleButton dspButton = createDspButton(dspType);
|
||||||
dspButton.addActionListener(cbActionListener);
|
dspButton.addActionListener(cbActionListener);
|
||||||
|
if ((Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) && dspType.equals(LocalDiskDSProcessor.getType())){
|
||||||
|
dspButton.setEnabled(false); //disable the button for local disk DSP when this is a multi user case
|
||||||
|
dspButton.setSelected(false);
|
||||||
|
shouldAddMultiUserWarning = true;
|
||||||
|
}
|
||||||
jPanel1.add(dspButton);
|
jPanel1.add(dspButton);
|
||||||
buttonGroup1.add(dspButton);
|
buttonGroup1.add(dspButton);
|
||||||
gridBagLayout.setConstraints(dspButton, constraints);
|
gridBagLayout.setConstraints(dspButton, constraints);
|
||||||
@ -130,7 +141,14 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
jPanel1.add(buttonTextSpacer);
|
jPanel1.add(buttonTextSpacer);
|
||||||
constraints.gridx++;
|
constraints.gridx++;
|
||||||
//Add the text area serving as a label to the right of the button
|
//Add the text area serving as a label to the right of the button
|
||||||
JTextArea myLabel = new JTextArea(dspType);
|
|
||||||
|
JTextArea myLabel = new JTextArea();
|
||||||
|
if (shouldAddMultiUserWarning) {
|
||||||
|
myLabel.setText(dspType + " - " + NbBundle.getMessage(this.getClass(), "AddImageWizardSelectDspVisual.multiUserWarning.text"));
|
||||||
|
myLabel.setEnabled(false); //gray out the text
|
||||||
|
} else {
|
||||||
|
myLabel.setText(dspType);
|
||||||
|
}
|
||||||
myLabel.setBackground(new Color(240, 240, 240));//matches background of panel
|
myLabel.setBackground(new Color(240, 240, 240));//matches background of panel
|
||||||
myLabel.setEditable(false);
|
myLabel.setEditable(false);
|
||||||
myLabel.setWrapStyleWord(true);
|
myLabel.setWrapStyleWord(true);
|
||||||
@ -169,12 +187,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dspList.add(ImageDSProcessor.getType());
|
dspList.add(ImageDSProcessor.getType());
|
||||||
if (Case.getCurrentCase().getCaseType() != Case.CaseType.MULTI_USER_CASE) {
|
dspList.add(LocalDiskDSProcessor.getType());
|
||||||
dspList.add(LocalDiskDSProcessor.getType());
|
|
||||||
} else {
|
|
||||||
// remove LocalDiskDSProcessor from list of DSPs
|
|
||||||
datasourceProcessorsMap.remove(LocalDiskDSProcessor.getType());
|
|
||||||
}
|
|
||||||
dspList.add(LocalFilesDSProcessor.getType());
|
dspList.add(LocalFilesDSProcessor.getType());
|
||||||
dspList.add(RawDSProcessor.getType());
|
dspList.add(RawDSProcessor.getType());
|
||||||
// now add any addtional DSPs that haven't already been added
|
// now add any addtional DSPs that haven't already been added
|
||||||
|
@ -140,8 +140,8 @@ CasePropertiesForm.updateCaseName.msgDlg.empty.msg=The caseName cannot be empty.
|
|||||||
CasePropertiesForm.updateCaseName.msgDlg.empty.title=Error
|
CasePropertiesForm.updateCaseName.msgDlg.empty.title=Error
|
||||||
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.msg=The Case Name cannot contain any of this following symbol\: \\ / \: * ? " < > |
|
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.msg=The Case Name cannot contain any of this following symbol\: \\ / \: * ? " < > |
|
||||||
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title=Error
|
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title=Error
|
||||||
CasePropertiesForm.updateCaseName.confMsg.msg=Are you sure want to update the case name from "{0}" to "{1}"?
|
CasePropertiesForm.updateCaseName.confMsg.msg=Are you sure you want to update the case name from "{0}" to "{1}"?
|
||||||
CasePropertiesForm.updateCaseName.confMsg.title=Create directory
|
CasePropertiesForm.updateCaseName.confMsg.title=Change Case Name
|
||||||
CueBannerPanel.title.text=Open Recent Case
|
CueBannerPanel.title.text=Open Recent Case
|
||||||
GeneralFilter.rawImageDesc.text=Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin)
|
GeneralFilter.rawImageDesc.text=Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin)
|
||||||
GeneralFilter.encaseImageDesc.text=Encase Images (*.e01)
|
GeneralFilter.encaseImageDesc.text=Encase Images (*.e01)
|
||||||
|
@ -104,8 +104,6 @@ CasePropertiesForm.updateCaseName.msgDlg.empty.msg=\u30b1\u30fc\u30b9\u540d\u306
|
|||||||
CasePropertiesForm.updateCaseName.msgDlg.empty.title=\u30a8\u30e9\u30fc
|
CasePropertiesForm.updateCaseName.msgDlg.empty.title=\u30a8\u30e9\u30fc
|
||||||
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.msg=\u30b1\u30fc\u30b9\u540d\u306b\u306f\u6b21\u306e\u8a18\u53f7\u3092\u542b\u3081\u307e\u305b\u3093\uff1a\\ / \: * ? " < > |
|
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.msg=\u30b1\u30fc\u30b9\u540d\u306b\u306f\u6b21\u306e\u8a18\u53f7\u3092\u542b\u3081\u307e\u305b\u3093\uff1a\\ / \: * ? " < > |
|
||||||
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title=\u30a8\u30e9\u30fc
|
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title=\u30a8\u30e9\u30fc
|
||||||
CasePropertiesForm.updateCaseName.confMsg.msg=\u30b1\u30fc\u30b9\u540d\u3092"{0}"\u304b\u3089"{1}"\u306b\u672c\u5f53\u306b\u66f4\u65b0\u3057\u307e\u3059\u304b\uff1f
|
|
||||||
CasePropertiesForm.updateCaseName.confMsg.title=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u4f5c\u6210
|
|
||||||
CueBannerPanel.title.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f
|
CueBannerPanel.title.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f
|
||||||
GeneralFilter.rawImageDesc.text=\u30ed\u30fc\u30a4\u30e1\u30fc\u30b8(*.img, *.dd, *.001, *.aa, *.raw, *.bin)
|
GeneralFilter.rawImageDesc.text=\u30ed\u30fc\u30a4\u30e1\u30fc\u30b8(*.img, *.dd, *.001, *.aa, *.raw, *.bin)
|
||||||
GeneralFilter.encaseImageDesc.text=\u30a8\u30f3\u30b1\u30fc\u30b9\u30a4\u30e1\u30fc\u30b8(*.e01)
|
GeneralFilter.encaseImageDesc.text=\u30a8\u30f3\u30b1\u30fc\u30b9\u30a4\u30e1\u30fc\u30b8(*.e01)
|
||||||
|
@ -568,7 +568,8 @@ public class Case {
|
|||||||
*
|
*
|
||||||
* IMPORTANT: This method should not be called in the event dispatch thread
|
* IMPORTANT: This method should not be called in the event dispatch thread
|
||||||
* (EDT).
|
* (EDT).
|
||||||
* @throws CaseActionException
|
*
|
||||||
|
* @throws CaseActionException
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
"# {0} - exception message", "Case.closeException.couldNotCloseCase=Error closing case: {0}",
|
"# {0} - exception message", "Case.closeException.couldNotCloseCase=Error closing case: {0}",
|
||||||
@ -637,6 +638,7 @@ public class Case {
|
|||||||
"# {0} - exception message", "Case.deleteException.couldNotDeleteCase=Could not delete case: {0}",
|
"# {0} - exception message", "Case.deleteException.couldNotDeleteCase=Could not delete case: {0}",
|
||||||
"Case.progressIndicatorTitle.deletingCase=Deleting Case",
|
"Case.progressIndicatorTitle.deletingCase=Deleting Case",
|
||||||
"Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first",
|
"Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first",
|
||||||
|
"Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
|
||||||
"Case.progressMessage.deletingTextIndex=Deleting text index...",
|
"Case.progressMessage.deletingTextIndex=Deleting text index...",
|
||||||
"Case.progressMessage.deletingCaseDatabase=Deleting case database...",
|
"Case.progressMessage.deletingCaseDatabase=Deleting case database...",
|
||||||
"Case.exceptionMessage.cancelled=Cancelled by user"
|
"Case.exceptionMessage.cancelled=Cancelled by user"
|
||||||
@ -672,7 +674,7 @@ public class Case {
|
|||||||
* First, acquire an exclusive case directory lock. The case
|
* First, acquire an exclusive case directory lock. The case
|
||||||
* cannot be deleted if another node has it open.
|
* cannot be deleted if another node has it open.
|
||||||
*/
|
*/
|
||||||
progressIndicator.start(Bundle.Case_progressMessage_acquiringLocks());
|
progressIndicator.start(Bundle.Case_progressMessage_checkingForOtherUser());
|
||||||
try (CoordinationService.Lock dirLock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, metadata.getCaseDirectory())) {
|
try (CoordinationService.Lock dirLock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, metadata.getCaseDirectory())) {
|
||||||
assert (null != dirLock);
|
assert (null != dirLock);
|
||||||
|
|
||||||
@ -723,8 +725,9 @@ public class Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanitizes the case name for use as a PostgreSQL database name and in
|
* Cleans up the display name for a case to make a suitable case name for
|
||||||
* ActiveMQ event channel (topic) names.
|
* use in case direcotry paths, coordination service locks, PostgreSQL
|
||||||
|
* database names, Active MQ message message channels, etc.
|
||||||
*
|
*
|
||||||
* PostgreSQL:
|
* PostgreSQL:
|
||||||
* http://www.postgresql.org/docs/9.4/static/sql-syntax-lexical.html 63
|
* http://www.postgresql.org/docs/9.4/static/sql-syntax-lexical.html 63
|
||||||
@ -741,7 +744,7 @@ public class Case {
|
|||||||
*
|
*
|
||||||
* @throws org.sleuthkit.autopsy.casemodule.Case.IllegalCaseNameException
|
* @throws org.sleuthkit.autopsy.casemodule.Case.IllegalCaseNameException
|
||||||
*/
|
*/
|
||||||
static String sanitizeCaseName(String caseName) throws IllegalCaseNameException {
|
public static String displayNameToCaseName(String caseName) throws IllegalCaseNameException {
|
||||||
|
|
||||||
String result;
|
String result;
|
||||||
|
|
||||||
@ -1604,7 +1607,7 @@ public class Case {
|
|||||||
"Case.progressIndicatorTitle.creatingCase=Creating Case",
|
"Case.progressIndicatorTitle.creatingCase=Creating Case",
|
||||||
"Case.progressIndicatorCancelButton.label=Cancel",
|
"Case.progressIndicatorCancelButton.label=Cancel",
|
||||||
"Case.progressMessage.preparing=Preparing...",
|
"Case.progressMessage.preparing=Preparing...",
|
||||||
"Case.progressMessage.acquiringLocks=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>"
|
"Case.progressMessage.openingCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>"
|
||||||
})
|
})
|
||||||
private void open(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException {
|
private void open(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException {
|
||||||
/*
|
/*
|
||||||
@ -1613,7 +1616,7 @@ public class Case {
|
|||||||
*/
|
*/
|
||||||
String caseName;
|
String caseName;
|
||||||
try {
|
try {
|
||||||
caseName = sanitizeCaseName(caseDisplayName);
|
caseName = displayNameToCaseName(caseDisplayName);
|
||||||
} catch (IllegalCaseNameException ex) {
|
} catch (IllegalCaseNameException ex) {
|
||||||
throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(Bundle.Case_exceptionMessage_illegalCaseName()), ex);
|
throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(Bundle.Case_exceptionMessage_illegalCaseName()), ex);
|
||||||
}
|
}
|
||||||
@ -1652,7 +1655,7 @@ public class Case {
|
|||||||
* First, acquire an exclusive case name lock to prevent two
|
* First, acquire an exclusive case name lock to prevent two
|
||||||
* nodes from creating the same case at the same time.
|
* nodes from creating the same case at the same time.
|
||||||
*/
|
*/
|
||||||
progressIndicator.start(Bundle.Case_progressMessage_acquiringLocks());
|
progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources());
|
||||||
try (CoordinationService.Lock nameLock = Case.acquireExclusiveCaseNameLock(caseName)) {
|
try (CoordinationService.Lock nameLock = Case.acquireExclusiveCaseNameLock(caseName)) {
|
||||||
assert (null != nameLock);
|
assert (null != nameLock);
|
||||||
/*
|
/*
|
||||||
@ -1872,7 +1875,7 @@ public class Case {
|
|||||||
* as long as this node has this case open, in order to prevent
|
* as long as this node has this case open, in order to prevent
|
||||||
* deletion of the case by another node.
|
* deletion of the case by another node.
|
||||||
*/
|
*/
|
||||||
progressIndicator.start(Bundle.Case_progressMessage_acquiringLocks());
|
progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources());
|
||||||
acquireSharedCaseDirLock(caseMetadata.getCaseDirectory());
|
acquireSharedCaseDirLock(caseMetadata.getCaseDirectory());
|
||||||
/*
|
/*
|
||||||
* Next, acquire an exclusive case resources lock to ensure only
|
* Next, acquire an exclusive case resources lock to ensure only
|
||||||
@ -2131,6 +2134,7 @@ public class Case {
|
|||||||
* @param progressIndicator A progress indicator.
|
* @param progressIndicator A progress indicator.
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
|
"Case.progressMessage.closingCaseResources=<html>Preparing to close case resources.<br>This may take time if another user is upgrading the case.</html>",
|
||||||
"Case.progressMessage.notifyingCaseEventSubscribers=Notifying case event subscribers...",
|
"Case.progressMessage.notifyingCaseEventSubscribers=Notifying case event subscribers...",
|
||||||
"Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
|
"Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
|
||||||
"Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
|
"Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
|
||||||
@ -2139,7 +2143,6 @@ public class Case {
|
|||||||
"Case.progressMessage.closingCaseDatabase=Closing case database...",
|
"Case.progressMessage.closingCaseDatabase=Closing case database...",
|
||||||
"Case.progressMessage.tearingDownTskErrorReporting=Tearing down SleuthKit error reporting..."
|
"Case.progressMessage.tearingDownTskErrorReporting=Tearing down SleuthKit error reporting..."
|
||||||
})
|
})
|
||||||
|
|
||||||
private void close() throws CaseActionException {
|
private void close() throws CaseActionException {
|
||||||
/*
|
/*
|
||||||
* Set up either a GUI progress indicator or a logging progress
|
* Set up either a GUI progress indicator or a logging progress
|
||||||
@ -2172,7 +2175,7 @@ public class Case {
|
|||||||
* node at a time can create/open/upgrade/close the case
|
* node at a time can create/open/upgrade/close the case
|
||||||
* resources.
|
* resources.
|
||||||
*/
|
*/
|
||||||
progressIndicator.start(Bundle.Case_progressMessage_acquiringLocks());
|
progressIndicator.start(Bundle.Case_progressMessage_closingCaseResources());
|
||||||
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseMetadata.getCaseName())) {
|
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseMetadata.getCaseName())) {
|
||||||
assert (null != resourcesLock);
|
assert (null != resourcesLock);
|
||||||
close(progressIndicator);
|
close(progressIndicator);
|
||||||
@ -2406,7 +2409,7 @@ public class Case {
|
|||||||
* An exception to throw when a case name with invalid characters is
|
* An exception to throw when a case name with invalid characters is
|
||||||
* encountered.
|
* encountered.
|
||||||
*/
|
*/
|
||||||
final static class IllegalCaseNameException extends Exception {
|
public final static class IllegalCaseNameException extends Exception {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ -204,17 +204,27 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate() throws WizardValidationException {
|
public void validate() throws WizardValidationException {
|
||||||
String caseName = getComponent().getCaseName();
|
String caseDisplayName = getComponent().getCaseName();
|
||||||
String caseParentDir = getComponent().getCaseParentDir();
|
String caseParentDir = getComponent().getCaseParentDir();
|
||||||
String caseDirPath = caseParentDir + caseName;
|
|
||||||
|
|
||||||
// check if case Name contain one of this following symbol:
|
// check if case Name contain one of this following symbol:
|
||||||
// \ / : * ? " < > |
|
// \ / : * ? " < > |
|
||||||
if (!Case.isValidName(caseName)) {
|
if (!Case.isValidName(caseDisplayName)) {
|
||||||
String errorMsg = NbBundle
|
String errorMsg = NbBundle
|
||||||
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.invalidSymbols");
|
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.invalidSymbols");
|
||||||
validationError(errorMsg);
|
validationError(errorMsg);
|
||||||
} else {
|
} else {
|
||||||
|
String caseName = "";
|
||||||
|
try {
|
||||||
|
caseName = Case.displayNameToCaseName(caseDisplayName);
|
||||||
|
} catch (Case.IllegalCaseNameException ex) {
|
||||||
|
String errorMsg = NbBundle
|
||||||
|
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.invalidSymbols");
|
||||||
|
validationError(errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
String caseDirPath = caseParentDir + caseName;
|
||||||
|
|
||||||
// check if the directory exist
|
// check if the directory exist
|
||||||
if (new File(caseDirPath).exists()) {
|
if (new File(caseDirPath).exists()) {
|
||||||
// throw a warning to enter new data or delete the existing directory
|
// throw a warning to enter new data or delete the existing directory
|
||||||
|
@ -177,7 +177,7 @@ public class SingleUserCaseConverter {
|
|||||||
// Create sanitized names for PostgreSQL and Solr
|
// Create sanitized names for PostgreSQL and Solr
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); //NON-NLS
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); //NON-NLS
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
String dbName = Case.sanitizeCaseName(icd.getNewCaseName()) + "_" + dateFormat.format(date); //NON-NLS
|
String dbName = Case.displayNameToCaseName(icd.getNewCaseName()) + "_" + dateFormat.format(date); //NON-NLS
|
||||||
icd.setPostgreSQLDbName(dbName);
|
icd.setPostgreSQLDbName(dbName);
|
||||||
|
|
||||||
// Copy items to new hostname folder structure
|
// Copy items to new hostname folder structure
|
||||||
|
@ -137,6 +137,8 @@ public class ImageUtils {
|
|||||||
OPEN_CV_LOADED = openCVLoadedTemp;
|
OPEN_CV_LOADED = openCVLoadedTemp;
|
||||||
SUPPORTED_IMAGE_EXTENSIONS.addAll(Arrays.asList(ImageIO.getReaderFileSuffixes()));
|
SUPPORTED_IMAGE_EXTENSIONS.addAll(Arrays.asList(ImageIO.getReaderFileSuffixes()));
|
||||||
SUPPORTED_IMAGE_EXTENSIONS.add("tec"); // Add JFIF .tec files
|
SUPPORTED_IMAGE_EXTENSIONS.add("tec"); // Add JFIF .tec files
|
||||||
|
SUPPORTED_IMAGE_EXTENSIONS.removeIf("db"::equals); // remove db files
|
||||||
|
|
||||||
SUPPORTED_IMAGE_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes()));
|
SUPPORTED_IMAGE_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes()));
|
||||||
/*
|
/*
|
||||||
* special cases and variants that we support, but don't get registered
|
* special cases and variants that we support, but don't get registered
|
||||||
@ -160,7 +162,7 @@ public class ImageUtils {
|
|||||||
private static FileTypeDetector fileTypeDetector;
|
private static FileTypeDetector fileTypeDetector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*Thread/Executor that saves generated thumbnails to disk in the background
|
* Thread/Executor that saves generated thumbnails to disk in the background
|
||||||
*/
|
*/
|
||||||
private static final Executor imageSaver
|
private static final Executor imageSaver
|
||||||
= Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
|
= Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
|
||||||
@ -297,12 +299,27 @@ public class ImageUtils {
|
|||||||
* @param content the content to generate a thumbnail for
|
* @param content the content to generate a thumbnail for
|
||||||
* @param iconSize the size (one side of a square) in pixels to generate
|
* @param iconSize the size (one side of a square) in pixels to generate
|
||||||
*
|
*
|
||||||
* @return a thumbnail for the given image or a default one if there was a
|
* @return A thumbnail for the given image or a default one if there was a
|
||||||
* problem making a thumbnail.
|
* problem making a thumbnail.
|
||||||
*/
|
*/
|
||||||
public static BufferedImage getThumbnail(Content content, int iconSize) {
|
public static BufferedImage getThumbnail(Content content, int iconSize) {
|
||||||
if (content instanceof AbstractFile) {
|
if (content instanceof AbstractFile) {
|
||||||
AbstractFile file = (AbstractFile) content;
|
AbstractFile file = (AbstractFile) content;
|
||||||
|
if (ImageUtils.isGIF(file)) {
|
||||||
|
/*
|
||||||
|
* Intercepting the image reading code for GIFs here allows us
|
||||||
|
* to rescale easily, but we lose animations.
|
||||||
|
*/
|
||||||
|
try (BufferedInputStream bufferedReadContentStream = getBufferedReadContentStream(file);) {
|
||||||
|
final BufferedImage image = ImageIO.read(bufferedReadContentStream);
|
||||||
|
if (image != null) {
|
||||||
|
return ScalrWrapper.resizeHighQuality(image, iconSize, iconSize);
|
||||||
|
}
|
||||||
|
} catch (IOException iOException) {
|
||||||
|
LOGGER.log(Level.WARNING, "Failed to get thumbnail for " + getContentPathSafe(content), iOException); //NON-NLS
|
||||||
|
}
|
||||||
|
return DEFAULT_THUMBNAIL;
|
||||||
|
}
|
||||||
|
|
||||||
Task<javafx.scene.image.Image> thumbnailTask = newGetThumbnailTask(file, iconSize, true);
|
Task<javafx.scene.image.Image> thumbnailTask = newGetThumbnailTask(file, iconSize, true);
|
||||||
thumbnailTask.run();
|
thumbnailTask.run();
|
||||||
@ -310,11 +327,22 @@ public class ImageUtils {
|
|||||||
return SwingFXUtils.fromFXImage(thumbnailTask.get(), null);
|
return SwingFXUtils.fromFXImage(thumbnailTask.get(), null);
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Failed to get thumbnail for " + getContentPathSafe(content), ex); //NON-NLS
|
LOGGER.log(Level.WARNING, "Failed to get thumbnail for " + getContentPathSafe(content), ex); //NON-NLS
|
||||||
return DEFAULT_THUMBNAIL;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return DEFAULT_THUMBNAIL;
|
|
||||||
}
|
}
|
||||||
|
return DEFAULT_THUMBNAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a BufferedInputStream wrapped around a ReadContentStream for the
|
||||||
|
* given AbstractFile.
|
||||||
|
*
|
||||||
|
* @param file The AbstractFile to get a stream for.
|
||||||
|
*
|
||||||
|
* @return A BufferedInputStream wrapped around a ReadContentStream for the
|
||||||
|
* given AbstractFile
|
||||||
|
*/
|
||||||
|
private static BufferedInputStream getBufferedReadContentStream(AbstractFile file) {
|
||||||
|
return new BufferedInputStream(new ReadContentInputStream(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -334,12 +362,12 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the location of the cached thumbnail for a file with the given fileID
|
* Get the location,as a java File, of the cached thumbnail for an file with
|
||||||
* as a java File. The returned File may not exist on disk yet.
|
* the given fileID . The returned File may not exist on disk yet.
|
||||||
*
|
*
|
||||||
* @param fileID the fileID to get the cached thumbnail location for
|
* @param fileID the fileID to get the cached thumbnail location for
|
||||||
*
|
*
|
||||||
* @return a File object representing the location of the cached thumbnail.
|
* @return A File object representing the location of the cached thumbnail.
|
||||||
* This file may not actually exist(yet). Returns null if there was
|
* This file may not actually exist(yet). Returns null if there was
|
||||||
* any problem getting the file, such as no case was open.
|
* any problem getting the file, such as no case was open.
|
||||||
*/
|
*/
|
||||||
@ -542,33 +570,30 @@ public class ImageUtils {
|
|||||||
* @see #getImageHeight(org.sleuthkit.datamodel.AbstractFile)
|
* @see #getImageHeight(org.sleuthkit.datamodel.AbstractFile)
|
||||||
*/
|
*/
|
||||||
private static <T> T getImageProperty(AbstractFile file, final String errorTemplate, PropertyExtractor<T> propertyExtractor) throws IOException {
|
private static <T> T getImageProperty(AbstractFile file, final String errorTemplate, PropertyExtractor<T> propertyExtractor) throws IOException {
|
||||||
try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) {
|
try (InputStream inputStream = getBufferedReadContentStream(file);
|
||||||
try (ImageInputStream input = ImageIO.createImageInputStream(inputStream)) {
|
ImageInputStream input = ImageIO.createImageInputStream(inputStream)) {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
IIOException iioException = new IIOException("Could not create ImageInputStream.");
|
IIOException iioException = new IIOException("Could not create ImageInputStream.");
|
||||||
LOGGER.log(Level.WARNING, errorTemplate + iioException.toString(), getContentPathSafe(file));
|
LOGGER.log(Level.WARNING, errorTemplate + iioException.toString(), getContentPathSafe(file));
|
||||||
throw iioException;
|
throw iioException;
|
||||||
}
|
}
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||||
|
|
||||||
if (readers.hasNext()) {
|
if (readers.hasNext()) {
|
||||||
ImageReader reader = readers.next();
|
ImageReader reader = readers.next();
|
||||||
reader.setInput(input);
|
reader.setInput(input);
|
||||||
try {
|
try {
|
||||||
|
return propertyExtractor.extract(reader);
|
||||||
return propertyExtractor.extract(reader);
|
} catch (IOException ex) {
|
||||||
} catch (IOException ex) {
|
LOGGER.log(Level.WARNING, errorTemplate + ex.toString(), getContentPathSafe(file));
|
||||||
LOGGER.log(Level.WARNING, errorTemplate + ex.toString(), getContentPathSafe(file));
|
throw ex;
|
||||||
throw ex;
|
} finally {
|
||||||
} finally {
|
reader.dispose();
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
IIOException iioException = new IIOException("No ImageReader found.");
|
|
||||||
LOGGER.log(Level.WARNING, errorTemplate + iioException.toString(), getContentPathSafe(file));
|
|
||||||
|
|
||||||
throw iioException;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
IIOException iioException = new IIOException("No ImageReader found.");
|
||||||
|
LOGGER.log(Level.WARNING, errorTemplate + iioException.toString(), getContentPathSafe(file));
|
||||||
|
throw iioException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -785,7 +810,7 @@ public class ImageUtils {
|
|||||||
protected javafx.scene.image.Image readImage() throws IOException {
|
protected javafx.scene.image.Image readImage() throws IOException {
|
||||||
if (ImageUtils.isGIF(file)) {
|
if (ImageUtils.isGIF(file)) {
|
||||||
//use JavaFX to directly read GIF to preserve potential animation
|
//use JavaFX to directly read GIF to preserve potential animation
|
||||||
javafx.scene.image.Image image = new javafx.scene.image.Image(new BufferedInputStream(new ReadContentInputStream(file)));
|
javafx.scene.image.Image image = new javafx.scene.image.Image(getBufferedReadContentStream(file));
|
||||||
if (image.isError() == false) {
|
if (image.isError() == false) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,8 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
T visit(KeywordHits.ListNode khsn);
|
T visit(KeywordHits.ListNode khsn);
|
||||||
|
|
||||||
T visit(KeywordHits.TermNode khmln);
|
T visit(KeywordHits.TermNode khmln);
|
||||||
|
|
||||||
|
T visit(KeywordHits.RegExpInstanceNode khmln);
|
||||||
|
|
||||||
T visit(HashsetHits.RootNode hhrn);
|
T visit(HashsetHits.RootNode hhrn);
|
||||||
|
|
||||||
@ -280,6 +282,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
public T visit(KeywordHits.ListNode khsn) {
|
public T visit(KeywordHits.ListNode khsn) {
|
||||||
return defaultVisit(khsn);
|
return defaultVisit(khsn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T visit(KeywordHits.RegExpInstanceNode khsn) {
|
||||||
|
return defaultVisit(khsn);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(KeywordHits.TermNode khmln) {
|
public T visit(KeywordHits.TermNode khmln) {
|
||||||
|
@ -64,17 +64,24 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
public static final String SIMPLE_REGEX_SEARCH = NbBundle
|
public static final String SIMPLE_REGEX_SEARCH = NbBundle
|
||||||
.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
|
.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
|
||||||
private final KeywordResults keywordResults;
|
private final KeywordResults keywordResults;
|
||||||
|
private final String DUMMY_INSTANCE = "DUMMY_EXACT_MATCH_INSTANCE";
|
||||||
|
|
||||||
public KeywordHits(SleuthkitCase skCase) {
|
public KeywordHits(SleuthkitCase skCase) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
keywordResults = new KeywordResults();
|
keywordResults = new KeywordResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* All of these maps and code assume the following:
|
||||||
|
* Regexps will have an 'instance' layer that shows the specific words that matched the regexp
|
||||||
|
* Exact match and substring will not have the instance layer and instead will have the specific hits
|
||||||
|
* below their term.
|
||||||
|
*/
|
||||||
|
|
||||||
private final class KeywordResults extends Observable {
|
private final class KeywordResults extends Observable {
|
||||||
|
|
||||||
// Map from listName/Type to Map of keyword to set of artifact Ids
|
// Map from listName/Type to Map of keywords/regexp to Map of instance terms to Set of artifact Ids
|
||||||
// NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
|
// NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
|
||||||
private final Map<String, Map<String, Set<Long>>> topLevelMap = new LinkedHashMap<>();
|
private final Map<String, Map<String, Map<String, Set<Long>>>> topLevelMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
KeywordResults() {
|
KeywordResults() {
|
||||||
update();
|
update();
|
||||||
@ -98,26 +105,66 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
Collections.sort(keywords);
|
Collections.sort(keywords);
|
||||||
return keywords;
|
return keywords;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Long> getArtifactIds(String listName, String keyword) {
|
List<String> getKeywordInstances(String listName, String keyword) {
|
||||||
|
List<String> instances;
|
||||||
synchronized (topLevelMap) {
|
synchronized (topLevelMap) {
|
||||||
return topLevelMap.get(listName).get(keyword);
|
instances = new ArrayList<>(topLevelMap.get(listName).get(keyword).keySet());
|
||||||
|
}
|
||||||
|
Collections.sort(instances);
|
||||||
|
return instances;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Long> getArtifactIds(String listName, String keyword, String keywordInstance) {
|
||||||
|
synchronized (topLevelMap) {
|
||||||
|
return topLevelMap.get(listName).get(keyword).get(keywordInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addRegExpToList(Map<String, Map<String, Set<Long>>> listMap, String regExp, String word, Long id) {
|
||||||
|
if (listMap.containsKey(regExp) == false) {
|
||||||
|
listMap.put(regExp, new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
Map<String, Set<Long>> instanceMap = listMap.get(regExp);
|
||||||
|
|
||||||
|
// get or create keyword instances entry.
|
||||||
|
if (instanceMap.containsKey(word) == false) {
|
||||||
|
instanceMap.put(word, new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add this ID to the instance
|
||||||
|
instanceMap.get(word).add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addExactMatchToList(Map<String, Map<String, Set<Long>>> listMap, String word, Long id) {
|
||||||
|
if (listMap.containsKey(word) == false) {
|
||||||
|
listMap.put(word, new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
Map<String, Set<Long>> instanceMap = listMap.get(word);
|
||||||
|
|
||||||
|
// get or create keyword instances entry.
|
||||||
|
// for exact match, use a dummy instance
|
||||||
|
if (instanceMap.containsKey(DUMMY_INSTANCE) == false) {
|
||||||
|
instanceMap.put(DUMMY_INSTANCE, new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add this ID to the instance
|
||||||
|
instanceMap.get(DUMMY_INSTANCE).add(id);
|
||||||
|
}
|
||||||
|
|
||||||
// populate maps based on artifactIds
|
// populate maps based on artifactIds
|
||||||
void populateMaps(Map<Long, Map<Long, String>> artifactIds) {
|
void populateMaps(Map<Long, Map<Long, String>> artifactIds) {
|
||||||
synchronized (topLevelMap) {
|
synchronized (topLevelMap) {
|
||||||
topLevelMap.clear();
|
topLevelMap.clear();
|
||||||
|
|
||||||
// map of list name to keword to artifact IDs
|
// map of list name to keword to artifact IDs
|
||||||
Map<String, Map<String, Set<Long>>> listsMap = new LinkedHashMap<>();
|
Map<String, Map<String, Map<String, Set<Long>>>> listsMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
// Map from from literal keyword to artifact IDs
|
// Map from from literal keyword to instances (which will be empty) to artifact IDs
|
||||||
Map<String, Set<Long>> literalMap = new LinkedHashMap<>();
|
Map<String, Map<String, Set<Long>>> literalMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
// Map from regex keyword artifact IDs
|
// Map from regex keyword artifact to instances to artifact IDs
|
||||||
Map<String, Set<Long>> regexMap = new LinkedHashMap<>();
|
Map<String, Map<String, Set<Long>>> regexMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
// top-level nodes
|
// top-level nodes
|
||||||
topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap);
|
topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap);
|
||||||
@ -131,34 +178,47 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()));
|
String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()));
|
||||||
String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()));
|
String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()));
|
||||||
String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()));
|
String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()));
|
||||||
|
// new in 4.4
|
||||||
|
String kwType = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()));
|
||||||
|
|
||||||
// part of a list
|
// part of a list
|
||||||
if (listName != null) {
|
if (listName != null) {
|
||||||
|
// get or create list entry
|
||||||
if (listsMap.containsKey(listName) == false) {
|
if (listsMap.containsKey(listName) == false) {
|
||||||
listsMap.put(listName, new LinkedHashMap<String, Set<Long>>());
|
listsMap.put(listName, new LinkedHashMap<>());
|
||||||
}
|
}
|
||||||
|
Map<String, Map<String, Set<Long>>> listMap = listsMap.get(listName);
|
||||||
Map<String, Set<Long>> listMap = listsMap.get(listName);
|
|
||||||
if (listMap.containsKey(word) == false) {
|
// substring, treated same as exact match
|
||||||
listMap.put(word, new HashSet<Long>());
|
// Enum for "1" is defined in KeywordSearch.java
|
||||||
|
if ((kwType != null) && (kwType.equals("1"))) {
|
||||||
|
// original term should be stored in reg
|
||||||
|
if (reg != null) {
|
||||||
|
addExactMatchToList(listMap, reg, id);
|
||||||
|
} else {
|
||||||
|
addExactMatchToList(listMap, word, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (reg != null) {
|
||||||
|
addRegExpToList(listMap, reg, word, id);
|
||||||
|
} else {
|
||||||
|
addExactMatchToList(listMap, word, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
listMap.get(word).add(id);
|
|
||||||
} // regular expression, single term
|
} // regular expression, single term
|
||||||
else if (reg != null) {
|
else if (reg != null) {
|
||||||
if (regexMap.containsKey(reg) == false) {
|
// substring is treated same as exact
|
||||||
regexMap.put(reg, new HashSet<Long>());
|
if ((kwType != null) && (kwType.equals("1"))) {
|
||||||
|
// original term should be stored in reg
|
||||||
|
addExactMatchToList(literalMap, reg, id);
|
||||||
|
} else {
|
||||||
|
addRegExpToList(regexMap, reg, word, id);
|
||||||
}
|
}
|
||||||
regexMap.get(reg).add(id);
|
|
||||||
} // literal, single term
|
} // literal, single term
|
||||||
else {
|
else {
|
||||||
if (literalMap.containsKey(word) == false) {
|
addExactMatchToList(literalMap, word, id);
|
||||||
literalMap.put(word, new HashSet<Long>());
|
}
|
||||||
}
|
|
||||||
literalMap.get(word).add(id);
|
|
||||||
}
|
|
||||||
topLevelMap.putAll(listsMap);
|
|
||||||
}
|
}
|
||||||
|
topLevelMap.putAll(listsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
setChanged();
|
setChanged();
|
||||||
@ -167,35 +227,43 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public void update() {
|
public void update() {
|
||||||
|
// maps Artifact ID to map of attribute types to attribute values
|
||||||
Map<Long, Map<Long, String>> artifactIds = new LinkedHashMap<>();
|
Map<Long, Map<Long, String>> artifactIds = new LinkedHashMap<>();
|
||||||
|
|
||||||
if (skCase == null) {
|
if (skCase == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// query attributes table for the ones that we need for the tree
|
||||||
int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
|
int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
|
||||||
int wordId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID();
|
int wordId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID();
|
||||||
int regexId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID();
|
int regexId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID();
|
||||||
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID();
|
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID();
|
||||||
String query = "SELECT blackboard_attributes.value_text,blackboard_attributes.artifact_id," //NON-NLS
|
String query = "SELECT blackboard_attributes.value_text,blackboard_attributes.value_int32,"
|
||||||
|
+ "blackboard_attributes.artifact_id," //NON-NLS
|
||||||
+ "blackboard_attributes.attribute_type_id FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
|
+ "blackboard_attributes.attribute_type_id FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
|
||||||
+ "(blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id AND " //NON-NLS
|
+ "(blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id AND " //NON-NLS
|
||||||
+ "blackboard_artifacts.artifact_type_id=" + artId //NON-NLS
|
+ "blackboard_artifacts.artifact_type_id=" + artId //NON-NLS
|
||||||
+ ") AND (attribute_type_id=" + setId + " OR " //NON-NLS
|
+ ") AND (attribute_type_id=" + setId + " OR " //NON-NLS
|
||||||
+ "attribute_type_id=" + wordId + " OR " //NON-NLS
|
+ "attribute_type_id=" + wordId + " OR " //NON-NLS
|
||||||
|
+ "attribute_type_id=" + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID() + " OR " //NON-NLS
|
||||||
+ "attribute_type_id=" + regexId + ")"; //NON-NLS
|
+ "attribute_type_id=" + regexId + ")"; //NON-NLS
|
||||||
|
|
||||||
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
||||||
ResultSet resultSet = dbQuery.getResultSet();
|
ResultSet resultSet = dbQuery.getResultSet();
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
String value = resultSet.getString("value_text"); //NON-NLS
|
String valueStr = resultSet.getString("value_text"); //NON-NLS
|
||||||
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
|
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
|
||||||
long typeId = resultSet.getLong("attribute_type_id"); //NON-NLS
|
long typeId = resultSet.getLong("attribute_type_id"); //NON-NLS
|
||||||
if (!artifactIds.containsKey(artifactId)) {
|
if (!artifactIds.containsKey(artifactId)) {
|
||||||
artifactIds.put(artifactId, new LinkedHashMap<Long, String>());
|
artifactIds.put(artifactId, new LinkedHashMap<Long, String>());
|
||||||
}
|
}
|
||||||
if (!value.equals("")) {
|
if (valueStr != null && !valueStr.equals("")) {
|
||||||
artifactIds.get(artifactId).put(typeId, value);
|
artifactIds.get(artifactId).put(typeId, valueStr);
|
||||||
|
} else {
|
||||||
|
// Keyword Search Type is an int
|
||||||
|
Long valueLong = resultSet.getLong("value_int32");
|
||||||
|
artifactIds.get(artifactId).put(typeId, valueLong.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | SQLException ex) {
|
} catch (TskCoreException | SQLException ex) {
|
||||||
@ -254,6 +322,9 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the list nodes
|
||||||
|
*/
|
||||||
private class ListFactory extends ChildFactory.Detachable<String> implements Observer {
|
private class ListFactory extends ChildFactory.Detachable<String> implements Observer {
|
||||||
|
|
||||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||||
@ -344,6 +415,9 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the keyword search lists (or default groupings if list was not given)
|
||||||
|
*/
|
||||||
public class ListNode extends DisplayableItemNode implements Observer {
|
public class ListNode extends DisplayableItemNode implements Observer {
|
||||||
|
|
||||||
private final String listName;
|
private final String listName;
|
||||||
@ -360,8 +434,10 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
private void updateDisplayName() {
|
private void updateDisplayName() {
|
||||||
int totalDescendants = 0;
|
int totalDescendants = 0;
|
||||||
for (String word : keywordResults.getKeywords(listName)) {
|
for (String word : keywordResults.getKeywords(listName)) {
|
||||||
Set<Long> ids = keywordResults.getArtifactIds(listName, word);
|
for (String instance : keywordResults.getKeywordInstances(listName, word)) {
|
||||||
totalDescendants += ids.size();
|
Set<Long> ids = keywordResults.getArtifactIds(listName, word, instance);
|
||||||
|
totalDescendants += ids.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.setDisplayName(listName + " (" + totalDescendants + ")");
|
super.setDisplayName(listName + " (" + totalDescendants + ")");
|
||||||
}
|
}
|
||||||
@ -409,6 +485,9 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the nodes that represent search terms
|
||||||
|
*/
|
||||||
private class TermFactory extends ChildFactory.Detachable<String> implements Observer {
|
private class TermFactory extends ChildFactory.Detachable<String> implements Observer {
|
||||||
|
|
||||||
private final String setName;
|
private final String setName;
|
||||||
@ -445,13 +524,16 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the search term or regexp that user searched for
|
||||||
|
*/
|
||||||
public class TermNode extends DisplayableItemNode implements Observer {
|
public class TermNode extends DisplayableItemNode implements Observer {
|
||||||
|
|
||||||
private final String setName;
|
private final String setName;
|
||||||
private final String keyword;
|
private final String keyword;
|
||||||
|
|
||||||
public TermNode(String setName, String keyword) {
|
public TermNode(String setName, String keyword) {
|
||||||
super(Children.create(new HitsFactory(setName, keyword), true), Lookups.singleton(keyword));
|
super(Children.create(new RegExpInstancesFactory(setName, keyword), true), Lookups.singleton(keyword));
|
||||||
super.setName(keyword);
|
super.setName(keyword);
|
||||||
this.setName = setName;
|
this.setName = setName;
|
||||||
this.keyword = keyword;
|
this.keyword = keyword;
|
||||||
@ -461,7 +543,175 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateDisplayName() {
|
private void updateDisplayName() {
|
||||||
super.setDisplayName(keyword + " (" + keywordResults.getArtifactIds(setName, keyword).size() + ")");
|
int totalDescendants = 0;
|
||||||
|
|
||||||
|
for (String instance : keywordResults.getKeywordInstances(setName, keyword)) {
|
||||||
|
Set<Long> ids = keywordResults.getArtifactIds(setName, keyword, instance);
|
||||||
|
totalDescendants += ids.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setDisplayName(keyword + " (" + totalDescendants + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
updateDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
List<String> instances = keywordResults.getKeywordInstances(setName, keyword);
|
||||||
|
// is this an exact match
|
||||||
|
if (instances.size() == 1 && instances.get(0).equals(DUMMY_INSTANCE)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
Sheet s = super.createSheet();
|
||||||
|
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||||
|
if (ss == null) {
|
||||||
|
ss = Sheet.createPropertiesSet();
|
||||||
|
s.put(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.name"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.displayName"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.desc"),
|
||||||
|
getDisplayName()));
|
||||||
|
|
||||||
|
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"),
|
||||||
|
keywordResults.getKeywordInstances(setName, keyword).size()));
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getItemType() {
|
||||||
|
return getClass().getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows us to pass in either longs or strings
|
||||||
|
// as they keys for different types of nodes at the
|
||||||
|
// same level. Probably a better way to do this, but
|
||||||
|
// it works.
|
||||||
|
class RegExpInstanceKey {
|
||||||
|
private final boolean isRegExp;
|
||||||
|
private String strKey;
|
||||||
|
private Long longKey;
|
||||||
|
public RegExpInstanceKey(String key) {
|
||||||
|
isRegExp = true;
|
||||||
|
strKey = key;
|
||||||
|
}
|
||||||
|
public RegExpInstanceKey(Long key) {
|
||||||
|
isRegExp = false;
|
||||||
|
longKey = key;
|
||||||
|
}
|
||||||
|
boolean isRegExp() {
|
||||||
|
return isRegExp;
|
||||||
|
}
|
||||||
|
Long getIdKey() {
|
||||||
|
return longKey;
|
||||||
|
}
|
||||||
|
String getRegExpKey() {
|
||||||
|
return strKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the nodes for a given regexp that represent the specific terms that were found
|
||||||
|
*/
|
||||||
|
public class RegExpInstancesFactory extends ChildFactory.Detachable<RegExpInstanceKey> implements Observer {
|
||||||
|
private final String keyword;
|
||||||
|
private final String setName;
|
||||||
|
|
||||||
|
public RegExpInstancesFactory(String setName, String keyword) {
|
||||||
|
super();
|
||||||
|
this.setName = setName;
|
||||||
|
this.keyword = keyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addNotify() {
|
||||||
|
keywordResults.addObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void removeNotify() {
|
||||||
|
keywordResults.deleteObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean createKeys(List<RegExpInstanceKey> list) {
|
||||||
|
List <String>instances = keywordResults.getKeywordInstances(setName, keyword);
|
||||||
|
// The keys are different depending on what we are displaying.
|
||||||
|
// regexp get another layer to show instances.
|
||||||
|
// Exact matches don't.
|
||||||
|
if ((instances.size() == 1) && (instances.get(0).equals(DUMMY_INSTANCE))) {
|
||||||
|
for (Long id : keywordResults.getArtifactIds(setName, keyword, DUMMY_INSTANCE) ) {
|
||||||
|
list.add(new RegExpInstanceKey(id));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (String instance : instances) {
|
||||||
|
list.add(new RegExpInstanceKey(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(RegExpInstanceKey key) {
|
||||||
|
// if it isn't not a regexp, then skip the 'instance' layer of the tree
|
||||||
|
if (key.isRegExp() == false) {
|
||||||
|
return createBlackboardArtifactNode(key.getIdKey());
|
||||||
|
} else {
|
||||||
|
return new RegExpInstanceNode(setName, keyword, key.getRegExpKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
refresh(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a specific term that was found from a regexp
|
||||||
|
*/
|
||||||
|
public class RegExpInstanceNode extends DisplayableItemNode implements Observer {
|
||||||
|
|
||||||
|
private final String setName;
|
||||||
|
private final String keyword;
|
||||||
|
private final String instance;
|
||||||
|
|
||||||
|
public RegExpInstanceNode(String setName, String keyword, String instance) {
|
||||||
|
super(Children.create(new HitsFactory(setName, keyword, instance), true), Lookups.singleton(keyword));
|
||||||
|
super.setName(keyword);
|
||||||
|
this.setName = setName;
|
||||||
|
this.keyword = keyword;
|
||||||
|
this.instance = instance;
|
||||||
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
|
||||||
|
updateDisplayName();
|
||||||
|
keywordResults.addObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplayName() {
|
||||||
|
int totalDescendants = keywordResults.getArtifactIds(setName, keyword, instance).size();
|
||||||
|
super.setDisplayName(instance + " (" + totalDescendants + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -496,7 +746,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"),
|
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"),
|
||||||
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"),
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"),
|
||||||
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"),
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"),
|
||||||
keywordResults.getArtifactIds(setName, keyword).size()));
|
keywordResults.getKeywordInstances(setName, keyword).size()));
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -507,15 +757,76 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a blackboard node for the given Keyword Hit artifact
|
||||||
|
* @param artifactId
|
||||||
|
* @return Node or null on error
|
||||||
|
*/
|
||||||
|
private BlackboardArtifactNode createBlackboardArtifactNode (Long artifactId) {
|
||||||
|
if (skCase == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
|
||||||
|
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
|
||||||
|
AbstractFile file;
|
||||||
|
try {
|
||||||
|
file = skCase.getAbstractFileById(art.getObjectID());
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It is possible to get a keyword hit on artifacts generated
|
||||||
|
// for the underlying image in which case MAC times are not
|
||||||
|
// available/applicable/useful.
|
||||||
|
if (file == null) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
n.addNodeProperty(new NodeProperty<>(
|
||||||
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"),
|
||||||
|
NbBundle.getMessage(this.getClass(),
|
||||||
|
"KeywordHits.createNodeForKey.modTime.displayName"),
|
||||||
|
NbBundle.getMessage(this.getClass(),
|
||||||
|
"KeywordHits.createNodeForKey.modTime.desc"),
|
||||||
|
ContentUtils.getStringTime(file.getMtime(), file)));
|
||||||
|
n.addNodeProperty(new NodeProperty<>(
|
||||||
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
|
||||||
|
NbBundle.getMessage(this.getClass(),
|
||||||
|
"KeywordHits.createNodeForKey.accessTime.displayName"),
|
||||||
|
NbBundle.getMessage(this.getClass(),
|
||||||
|
"KeywordHits.createNodeForKey.accessTime.desc"),
|
||||||
|
ContentUtils.getStringTime(file.getAtime(), file)));
|
||||||
|
n.addNodeProperty(new NodeProperty<>(
|
||||||
|
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
|
||||||
|
NbBundle.getMessage(this.getClass(),
|
||||||
|
"KeywordHits.createNodeForKey.chgTime.displayName"),
|
||||||
|
NbBundle.getMessage(this.getClass(),
|
||||||
|
"KeywordHits.createNodeForKey.chgTime.desc"),
|
||||||
|
ContentUtils.getStringTime(file.getCtime(), file)));
|
||||||
|
return n;
|
||||||
|
} catch (TskException ex) {
|
||||||
|
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates nodes for individual files that had hits
|
||||||
|
*/
|
||||||
public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
|
public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
|
||||||
|
|
||||||
private final String keyword;
|
private final String keyword;
|
||||||
private final String setName;
|
private final String setName;
|
||||||
|
private final String instance;
|
||||||
|
|
||||||
public HitsFactory(String setName, String keyword) {
|
public HitsFactory(String setName, String keyword, String instance) {
|
||||||
super();
|
super();
|
||||||
this.setName = setName;
|
this.setName = setName;
|
||||||
this.keyword = keyword;
|
this.keyword = keyword;
|
||||||
|
this.instance = instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -530,60 +841,13 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<Long> list) {
|
protected boolean createKeys(List<Long> list) {
|
||||||
list.addAll(keywordResults.getArtifactIds(setName, keyword));
|
list.addAll(keywordResults.getArtifactIds(setName, keyword, instance));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(Long artifactId) {
|
protected Node createNodeForKey(Long artifactId) {
|
||||||
if (skCase == null) {
|
return createBlackboardArtifactNode(artifactId);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
|
|
||||||
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
|
|
||||||
AbstractFile file;
|
|
||||||
try {
|
|
||||||
file = skCase.getAbstractFileById(art.getObjectID());
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is possible to get a keyword hit on artifacts generated
|
|
||||||
// for the underlying image in which case MAC times are not
|
|
||||||
// available/applicable/useful.
|
|
||||||
if (file == null) {
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
n.addNodeProperty(new NodeProperty<>(
|
|
||||||
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"),
|
|
||||||
NbBundle.getMessage(this.getClass(),
|
|
||||||
"KeywordHits.createNodeForKey.modTime.displayName"),
|
|
||||||
NbBundle.getMessage(this.getClass(),
|
|
||||||
"KeywordHits.createNodeForKey.modTime.desc"),
|
|
||||||
ContentUtils.getStringTime(file.getMtime(), file)));
|
|
||||||
n.addNodeProperty(new NodeProperty<>(
|
|
||||||
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
|
|
||||||
NbBundle.getMessage(this.getClass(),
|
|
||||||
"KeywordHits.createNodeForKey.accessTime.displayName"),
|
|
||||||
NbBundle.getMessage(this.getClass(),
|
|
||||||
"KeywordHits.createNodeForKey.accessTime.desc"),
|
|
||||||
ContentUtils.getStringTime(file.getAtime(), file)));
|
|
||||||
n.addNodeProperty(new NodeProperty<>(
|
|
||||||
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
|
|
||||||
NbBundle.getMessage(this.getClass(),
|
|
||||||
"KeywordHits.createNodeForKey.chgTime.displayName"),
|
|
||||||
NbBundle.getMessage(this.getClass(),
|
|
||||||
"KeywordHits.createNodeForKey.chgTime.desc"),
|
|
||||||
ContentUtils.getStringTime(file.getCtime(), file)));
|
|
||||||
return n;
|
|
||||||
} catch (TskException ex) {
|
|
||||||
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,24 +28,25 @@ class ProgressPanel extends javax.swing.JPanel {
|
|||||||
ProgressPanel() {
|
ProgressPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
this.progressBar.setMinimum(0);
|
this.progressBar.setMinimum(0);
|
||||||
|
this.progressBar.setIndeterminate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMessage(String message) {
|
void setMessage(String message) {
|
||||||
this.progressMessage.setText(message);
|
this.progressMessage.setText(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInderminate(boolean indeterminate) {
|
void setInderminate(boolean indeterminate) {
|
||||||
this.progressBar.setIndeterminate(indeterminate);
|
this.progressBar.setIndeterminate(indeterminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMaximum(int max) {
|
void setMaximum(int max) {
|
||||||
this.progressBar.setMaximum(max);
|
this.progressBar.setMaximum(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCurrent(int current) {
|
void setCurrent(int current) {
|
||||||
this.progressBar.setValue(current);
|
this.progressBar.setValue(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* This method is called from within the constructor to initialize the form.
|
||||||
* WARNING: Do NOT modify this code. The content of this method is always
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
@ -25,7 +25,9 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
@ -36,6 +38,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||||
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -52,6 +56,9 @@ class CallLogAnalyzer {
|
|||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
||||||
private static final Logger logger = Logger.getLogger(CallLogAnalyzer.class.getName());
|
private static final Logger logger = Logger.getLogger(CallLogAnalyzer.class.getName());
|
||||||
private static Blackboard blackboard;
|
private static Blackboard blackboard;
|
||||||
|
|
||||||
|
private static final IngestServices services = IngestServices.getInstance();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the names of tables that potentially hold call logs in the dbs
|
* the names of tables that potentially hold call logs in the dbs
|
||||||
@ -85,6 +92,8 @@ class CallLogAnalyzer {
|
|||||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||||
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
|
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
|
||||||
Statement statement = connection.createStatement();) {
|
Statement statement = connection.createStatement();) {
|
||||||
|
|
||||||
@ -112,6 +121,8 @@ class CallLogAnalyzer {
|
|||||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, directionString));
|
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, directionString));
|
||||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, moduleName, name));
|
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, moduleName, name));
|
||||||
|
|
||||||
|
bbartifacts.add(bba);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// index the artifact for keyword search
|
// index the artifact for keyword search
|
||||||
blackboard.indexArtifact(bba);
|
blackboard.indexArtifact(bba);
|
||||||
@ -131,6 +142,13 @@ class CallLogAnalyzer {
|
|||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.log(Level.SEVERE, "Could not parse call log; error connecting to db " + DatabasePath, e); //NON-NLS
|
logger.log(Level.SEVERE, "Could not parse call log; error connecting to db " + DatabasePath, e); //NON-NLS
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
if (!bbartifacts.isEmpty()) {
|
||||||
|
services.fireModuleDataEvent(new ModuleDataEvent(
|
||||||
|
moduleName,
|
||||||
|
BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG, bbartifacts));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static enum CallDirection {
|
private static enum CallDirection {
|
||||||
|
@ -25,6 +25,8 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
@ -35,6 +37,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||||
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -49,6 +53,7 @@ class ContactAnalyzer {
|
|||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
||||||
private static final Logger logger = Logger.getLogger(ContactAnalyzer.class.getName());
|
private static final Logger logger = Logger.getLogger(ContactAnalyzer.class.getName());
|
||||||
|
private static final IngestServices services = IngestServices.getInstance();
|
||||||
|
|
||||||
public static void findContacts(Content dataSource, FileManager fileManager,
|
public static void findContacts(Content dataSource, FileManager fileManager,
|
||||||
IngestJobContext context) {
|
IngestJobContext context) {
|
||||||
@ -98,7 +103,8 @@ class ContactAnalyzer {
|
|||||||
logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS
|
logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
// get display_name, mimetype(email or phone number) and data1 (phonenumber or email address depending on mimetype)
|
// get display_name, mimetype(email or phone number) and data1 (phonenumber or email address depending on mimetype)
|
||||||
//sorted by name, so phonenumber/email would be consecutive for a person if they exist.
|
//sorted by name, so phonenumber/email would be consecutive for a person if they exist.
|
||||||
@ -152,6 +158,8 @@ class ContactAnalyzer {
|
|||||||
}
|
}
|
||||||
oldName = name;
|
oldName = name;
|
||||||
|
|
||||||
|
bbartifacts.add(bba);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// index the artifact for keyword search
|
// index the artifact for keyword search
|
||||||
blackboard.indexArtifact(bba);
|
blackboard.indexArtifact(bba);
|
||||||
@ -167,6 +175,12 @@ class ContactAnalyzer {
|
|||||||
} catch (TskCoreException e) {
|
} catch (TskCoreException e) {
|
||||||
logger.log(Level.SEVERE, "Error posting to blackboard", e); //NON-NLS
|
logger.log(Level.SEVERE, "Error posting to blackboard", e); //NON-NLS
|
||||||
} finally {
|
} finally {
|
||||||
|
if (!bbartifacts.isEmpty()) {
|
||||||
|
services.fireModuleDataEvent(new ModuleDataEvent(
|
||||||
|
moduleName,
|
||||||
|
BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT, bbartifacts));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (resultSet != null) {
|
if (resultSet != null) {
|
||||||
resultSet.close();
|
resultSet.close();
|
||||||
|
@ -24,6 +24,8 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
@ -35,6 +37,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||||
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -48,6 +52,7 @@ class TextMessageAnalyzer {
|
|||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
||||||
private static final Logger logger = Logger.getLogger(TextMessageAnalyzer.class.getName());
|
private static final Logger logger = Logger.getLogger(TextMessageAnalyzer.class.getName());
|
||||||
|
private static final IngestServices services = IngestServices.getInstance();
|
||||||
private static Blackboard blackboard;
|
private static Blackboard blackboard;
|
||||||
|
|
||||||
public static void findTexts(Content dataSource, FileManager fileManager,
|
public static void findTexts(Content dataSource, FileManager fileManager,
|
||||||
@ -88,6 +93,7 @@ class TextMessageAnalyzer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
resultSet = statement.executeQuery(
|
resultSet = statement.executeQuery(
|
||||||
"SELECT address,date,read,type,subject,body FROM sms;"); //NON-NLS
|
"SELECT address,date,read,type,subject,body FROM sms;"); //NON-NLS
|
||||||
@ -127,6 +133,8 @@ class TextMessageAnalyzer {
|
|||||||
NbBundle.getMessage(TextMessageAnalyzer.class,
|
NbBundle.getMessage(TextMessageAnalyzer.class,
|
||||||
"TextMessageAnalyzer.bbAttribute.smsMessage")));
|
"TextMessageAnalyzer.bbAttribute.smsMessage")));
|
||||||
|
|
||||||
|
bbartifacts.add(bba);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// index the artifact for keyword search
|
// index the artifact for keyword search
|
||||||
blackboard.indexArtifact(bba);
|
blackboard.indexArtifact(bba);
|
||||||
@ -139,6 +147,12 @@ class TextMessageAnalyzer {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.SEVERE, "Error parsing text messages to Blackboard", e); //NON-NLS
|
logger.log(Level.SEVERE, "Error parsing text messages to Blackboard", e); //NON-NLS
|
||||||
} finally {
|
} finally {
|
||||||
|
if (!bbartifacts.isEmpty()) {
|
||||||
|
services.fireModuleDataEvent(new ModuleDataEvent(
|
||||||
|
moduleName,
|
||||||
|
BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE, bbartifacts));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (resultSet != null) {
|
if (resultSet != null) {
|
||||||
resultSet.close();
|
resultSet.close();
|
||||||
|
@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TY
|
|||||||
*/
|
*/
|
||||||
public class FilesSetPanel extends javax.swing.JPanel {
|
public class FilesSetPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
@NbBundle.Messages({"FilesSetPanel.ingest.title=File Ingest Filter", "FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filter(s)...", "FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named."})
|
@NbBundle.Messages({"FilesSetPanel.ingest.title=File Ingest Filter", "FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters...", "FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named."})
|
||||||
|
|
||||||
private static final String CREATE_NEW_FILE_INGEST_FILTER = Bundle.FilesSetPanel_ingest_createNewFilter();
|
private static final String CREATE_NEW_FILE_INGEST_FILTER = Bundle.FilesSetPanel_ingest_createNewFilter();
|
||||||
private final String mustBeNamedErrorText;
|
private final String mustBeNamedErrorText;
|
||||||
|
@ -68,6 +68,7 @@ import org.apache.solr.client.solrj.impl.HttpSolrServer;
|
|||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case.IllegalCaseNameException;
|
||||||
import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
||||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||||
@ -200,6 +201,12 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
casesToManifests = new HashMap<>();
|
casesToManifests = new HashMap<>();
|
||||||
pendingJobs = new ArrayList<>();
|
pendingJobs = new ArrayList<>();
|
||||||
completedJobs = new ArrayList<>();
|
completedJobs = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
RuntimeProperties.setRunningWithGUI(false);
|
||||||
|
SYS_LOGGER.log(Level.INFO, "Set running with desktop GUI runtime property to false");
|
||||||
|
} catch (RuntimeProperties.RuntimePropertiesException ex) {
|
||||||
|
SYS_LOGGER.log(Level.SEVERE, "Failed to set running with desktop GUI runtime property to false", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -229,13 +236,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
jobProcessingTaskFuture = jobProcessingExecutor.submit(jobProcessingTask);
|
jobProcessingTaskFuture = jobProcessingExecutor.submit(jobProcessingTask);
|
||||||
jobStatusPublishingExecutor.scheduleAtFixedRate(new PeriodicJobStatusEventTask(), JOB_STATUS_EVENT_INTERVAL_SECONDS, JOB_STATUS_EVENT_INTERVAL_SECONDS, TimeUnit.SECONDS);
|
jobStatusPublishingExecutor.scheduleAtFixedRate(new PeriodicJobStatusEventTask(), JOB_STATUS_EVENT_INTERVAL_SECONDS, JOB_STATUS_EVENT_INTERVAL_SECONDS, TimeUnit.SECONDS);
|
||||||
eventPublisher.addSubscriber(EVENT_LIST, instance);
|
eventPublisher.addSubscriber(EVENT_LIST, instance);
|
||||||
try {
|
|
||||||
RuntimeProperties.setRunningWithGUI(false);
|
|
||||||
SYS_LOGGER.log(Level.INFO, "Set running with desktop GUI runtime property to false");
|
|
||||||
} catch (RuntimeProperties.RuntimePropertiesException ex) {
|
|
||||||
SYS_LOGGER.log(Level.SEVERE, "Failed to set running with desktop GUI runtime property to false", ex);
|
|
||||||
throw new AutoIngestManagerStartupException("Failed to set running with desktop GUI runtime property to false", ex);
|
|
||||||
}
|
|
||||||
state = State.RUNNING;
|
state = State.RUNNING;
|
||||||
errorState = ErrorState.NONE;
|
errorState = ErrorState.NONE;
|
||||||
}
|
}
|
||||||
@ -1923,17 +1923,23 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
*/
|
*/
|
||||||
private Case openCase() throws CoordinationServiceException, CaseManagementException, InterruptedException {
|
private Case openCase() throws CoordinationServiceException, CaseManagementException, InterruptedException {
|
||||||
Manifest manifest = currentJob.getManifest();
|
Manifest manifest = currentJob.getManifest();
|
||||||
String caseName = manifest.getCaseName();
|
String caseDisplayName = manifest.getCaseName();
|
||||||
SYS_LOGGER.log(Level.INFO, "Opening case {0} for {1}", new Object[]{caseName, manifest.getFilePath()});
|
String caseName;
|
||||||
|
try {
|
||||||
|
caseName = Case.displayNameToCaseName(caseDisplayName);
|
||||||
|
} catch (IllegalCaseNameException ex) {
|
||||||
|
throw new CaseManagementException(String.format("Error creating or opening case %s for %s", manifest.getCaseName(), manifest.getFilePath()), ex);
|
||||||
|
}
|
||||||
|
SYS_LOGGER.log(Level.INFO, "Opening case {0} ({1}) for {2}", new Object[]{caseDisplayName, caseName, manifest.getFilePath()});
|
||||||
currentJob.setStage(AutoIngestJob.Stage.OPENING_CASE);
|
currentJob.setStage(AutoIngestJob.Stage.OPENING_CASE);
|
||||||
try {
|
try {
|
||||||
Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, caseName);
|
Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, caseName);
|
||||||
if (null != caseDirectoryPath) {
|
if (null != caseDirectoryPath) {
|
||||||
Path metadataFilePath = caseDirectoryPath.resolve(manifest.getCaseName() + CaseMetadata.getFileExtension());
|
Path metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension());
|
||||||
Case.openAsCurrentCase(metadataFilePath.toString());
|
Case.openAsCurrentCase(metadataFilePath.toString());
|
||||||
} else {
|
} else {
|
||||||
caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName);
|
caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName);
|
||||||
Case.createAsCurrentCase(caseDirectoryPath.toString(), currentJob.getManifest().getCaseName(), "", "", CaseType.MULTI_USER_CASE);
|
Case.createAsCurrentCase(caseDirectoryPath.toString(), caseName, "", "", CaseType.MULTI_USER_CASE);
|
||||||
/*
|
/*
|
||||||
* Sleep a bit before releasing the lock to ensure that the
|
* Sleep a bit before releasing the lock to ensure that the
|
||||||
* new case folder is visible on the network.
|
* new case folder is visible on the network.
|
||||||
@ -1946,13 +1952,13 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
return caseForJob;
|
return caseForJob;
|
||||||
|
|
||||||
} catch (CaseActionException ex) {
|
} catch (CaseActionException ex) {
|
||||||
throw new CaseManagementException(String.format("Error creating or opening case %s for %s", manifest.getCaseName(), manifest.getFilePath()), ex);
|
throw new CaseManagementException(String.format("Error creating or opening case %s (%s) for %s", manifest.getCaseName(), caseName, manifest.getFilePath()), ex);
|
||||||
} catch (IllegalStateException ex) {
|
} catch (IllegalStateException ex) {
|
||||||
/*
|
/*
|
||||||
* Deal with the unfortunate fact that Case.getCurrentCase
|
* Deal with the unfortunate fact that Case.getCurrentCase
|
||||||
* throws IllegalStateException.
|
* throws IllegalStateException.
|
||||||
*/
|
*/
|
||||||
throw new CaseManagementException(String.format("Error getting current case %s for %s", manifest.getCaseName(), manifest.getFilePath()), ex);
|
throw new CaseManagementException(String.format("Error getting current case %s (%s) for %s", caseName, manifest.getCaseName(), manifest.getFilePath()), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2345,7 +2351,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
throw new AnalysisStartupException("Ingest manager error starting job", ingestJobStartResult.getStartupException());
|
throw new AnalysisStartupException("Ingest manager error starting job", ingestJobStartResult.getStartupException());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (String warning : ingestJobSettings.getWarnings()) {
|
for (String warning : settingsWarnings) {
|
||||||
SYS_LOGGER.log(Level.SEVERE, "Ingest job settings error for {0}: {1}", new Object[]{manifestPath, warning});
|
SYS_LOGGER.log(Level.SEVERE, "Ingest job settings error for {0}: {1}", new Object[]{manifestPath, warning});
|
||||||
}
|
}
|
||||||
currentJob.setErrorsOccurred(true);
|
currentJob.setErrorsOccurred(true);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2015 Basis Technology Corp.
|
* Copyright 2013-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||||
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
||||||
|
|
||||||
@ -45,12 +46,18 @@ final class PathUtils {
|
|||||||
* @return The path of the case folder, or null if it is not found.
|
* @return The path of the case folder, or null if it is not found.
|
||||||
*/
|
*/
|
||||||
static Path findCaseDirectory(Path folderToSearch, String caseName) {
|
static Path findCaseDirectory(Path folderToSearch, String caseName) {
|
||||||
|
String sanitizedCaseName;
|
||||||
|
try {
|
||||||
|
sanitizedCaseName = Case.displayNameToCaseName(caseName);
|
||||||
|
} catch (Case.IllegalCaseNameException unused) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
File searchFolder = new File(folderToSearch.toString());
|
File searchFolder = new File(folderToSearch.toString());
|
||||||
if (!searchFolder.isDirectory()) {
|
if (!searchFolder.isDirectory()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Path caseFolderPath = null;
|
Path caseFolderPath = null;
|
||||||
String[] candidateFolders = searchFolder.list(new CaseFolderFilter(caseName));
|
String[] candidateFolders = searchFolder.list(new CaseFolderFilter(sanitizedCaseName));
|
||||||
long mostRecentModified = 0;
|
long mostRecentModified = 0;
|
||||||
for (String candidateFolder : candidateFolders) {
|
for (String candidateFolder : candidateFolders) {
|
||||||
File file = new File(candidateFolder);
|
File file = new File(candidateFolder);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-16 Basis Technology Corp.
|
* Copyright 2011-17 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -182,7 +182,7 @@ public final class ImageGalleryController implements Executor {
|
|||||||
return groupManager;
|
return groupManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DrawableDB getDatabase() {
|
synchronized public DrawableDB getDatabase() {
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,7 +306,7 @@ public final class ImageGalleryController implements Executor {
|
|||||||
"ImageGalleryController.noGroupsDlg.msg6=There are no fully analyzed groups to display:"
|
"ImageGalleryController.noGroupsDlg.msg6=There are no fully analyzed groups to display:"
|
||||||
+ " the current Group By setting resulted in no groups, "
|
+ " the current Group By setting resulted in no groups, "
|
||||||
+ "or no groups are fully analyzed but ingest is not running."})
|
+ "or no groups are fully analyzed but ingest is not running."})
|
||||||
public void checkForGroups() {
|
synchronized private void checkForGroups() {
|
||||||
if (groupManager.getAnalyzedGroups().isEmpty()) {
|
if (groupManager.getAnalyzedGroups().isEmpty()) {
|
||||||
if (IngestManager.getInstance().isIngestRunning()) {
|
if (IngestManager.getInstance().isIngestRunning()) {
|
||||||
if (listeningEnabled.get() == false) {
|
if (listeningEnabled.get() == false) {
|
||||||
@ -951,13 +951,15 @@ public final class ImageGalleryController implements Executor {
|
|||||||
if (isListeningEnabled()) {
|
if (isListeningEnabled()) {
|
||||||
if (file.isFile()) {
|
if (file.isFile()) {
|
||||||
try {
|
try {
|
||||||
if (ImageGalleryModule.isDrawableAndNotKnown(file)) {
|
synchronized (ImageGalleryController.this) {
|
||||||
//this file should be included and we don't already know about it from hash sets (NSRL)
|
if (ImageGalleryModule.isDrawableAndNotKnown(file)) {
|
||||||
queueDBWorkerTask(new UpdateFileTask(file, db));
|
//this file should be included and we don't already know about it from hash sets (NSRL)
|
||||||
} else if (FileTypeUtils.getAllSupportedExtensions().contains(file.getNameExtension())) {
|
queueDBWorkerTask(new UpdateFileTask(file, db));
|
||||||
//doing this check results in fewer tasks queued up, and faster completion of db update
|
} else if (FileTypeUtils.getAllSupportedExtensions().contains(file.getNameExtension())) {
|
||||||
//this file would have gotten scooped up in initial grab, but actually we don't need it
|
//doing this check results in fewer tasks queued up, and faster completion of db update
|
||||||
queueDBWorkerTask(new RemoveFileTask(file, db));
|
//this file would have gotten scooped up in initial grab, but actually we don't need it
|
||||||
|
queueDBWorkerTask(new RemoveFileTask(file, db));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | FileTypeDetector.FileTypeDetectorInitException ex) {
|
} catch (TskCoreException | FileTypeDetector.FileTypeDetectorInitException ex) {
|
||||||
//TODO: What to do here?
|
//TODO: What to do here?
|
||||||
|
@ -132,7 +132,7 @@ class DropdownToolbar extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void maybeShowListsPopup(MouseEvent evt) {
|
private void maybeShowListsPopup(MouseEvent evt) {
|
||||||
if (!active) {
|
if (!active || !listsButton.isEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
|
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
|
||||||
@ -142,7 +142,7 @@ class DropdownToolbar extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void maybeShowSearchPopup(MouseEvent evt) {
|
private void maybeShowSearchPopup(MouseEvent evt) {
|
||||||
if (!active) {
|
if (!active || !searchDropButton.isEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
|
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
|
||||||
@ -159,41 +159,50 @@ class DropdownToolbar extends javax.swing.JPanel {
|
|||||||
String changed = evt.getPropertyName();
|
String changed = evt.getPropertyName();
|
||||||
if (changed.equals(Case.Events.CURRENT_CASE.toString())) {
|
if (changed.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||||
if (null != evt.getNewValue()) {
|
if (null != evt.getNewValue()) {
|
||||||
|
boolean disableSearch = false;
|
||||||
/*
|
/*
|
||||||
* A case has been opened.
|
* A case has been opened.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
Server server = KeywordSearch.getServer();
|
Server server = KeywordSearch.getServer();
|
||||||
Index indexInfo = server.getIndexInfo();
|
if (server.coreIsOpen() == false) {
|
||||||
if (server.coreIsOpen() && IndexFinder.getCurrentSolrVersion().equals(indexInfo.getSolrVersion())) {
|
disableSearch = true;
|
||||||
/*
|
|
||||||
* Solr version is current, so check the Solr
|
|
||||||
* schema version and selectively enable the ad
|
|
||||||
* hoc search UI components.
|
|
||||||
*/
|
|
||||||
boolean schemaIsCurrent = IndexFinder.getCurrentSchemaVersion().equals(indexInfo.getSchemaVersion());
|
|
||||||
listsButton.setEnabled(schemaIsCurrent);
|
|
||||||
searchDropButton.setEnabled(true);
|
|
||||||
dropPanel.setRegexSearchEnabled(schemaIsCurrent);
|
|
||||||
active = true;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Unsupported Solr version, disable the ad hoc
|
|
||||||
* search UI components.
|
|
||||||
*/
|
|
||||||
searchDropButton.setEnabled(false);
|
|
||||||
listsButton.setEnabled(false);
|
|
||||||
active = false;
|
|
||||||
}
|
}
|
||||||
} catch (KeywordSearchModuleException ex) {
|
else {
|
||||||
|
Index indexInfo = server.getIndexInfo();
|
||||||
|
if (IndexFinder.getCurrentSolrVersion().equals(indexInfo.getSolrVersion())) {
|
||||||
|
/*
|
||||||
|
* Solr version is current, so check the Solr
|
||||||
|
* schema version and selectively enable the ad
|
||||||
|
* hoc search UI components.
|
||||||
|
*/
|
||||||
|
boolean schemaIsCurrent = IndexFinder.getCurrentSchemaVersion().equals(indexInfo.getSchemaVersion());
|
||||||
|
listsButton.setEnabled(schemaIsCurrent);
|
||||||
|
searchDropButton.setEnabled(true);
|
||||||
|
dropPanel.setRegexSearchEnabled(schemaIsCurrent);
|
||||||
|
active = true;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Unsupported Solr version, disable the ad hoc
|
||||||
|
* search UI components.
|
||||||
|
*/
|
||||||
|
disableSearch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NoOpenCoreException ex) {
|
||||||
/*
|
/*
|
||||||
* Error, disable the ad hoc search UI components.
|
* Error, disable the ad hoc search UI components.
|
||||||
*/
|
*/
|
||||||
logger.log(Level.SEVERE, "Error getting text index info", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Error getting text index info", ex); //NON-NLS
|
||||||
|
disableSearch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disableSearch) {
|
||||||
searchDropButton.setEnabled(false);
|
searchDropButton.setEnabled(false);
|
||||||
listsButton.setEnabled(false);
|
listsButton.setEnabled(false);
|
||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* A case has been closed.
|
* A case has been closed.
|
||||||
|
@ -327,6 +327,9 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
*/
|
*/
|
||||||
private boolean solrHasContent(Long objectId) {
|
private boolean solrHasContent(Long objectId) {
|
||||||
final Server solrServer = KeywordSearch.getServer();
|
final Server solrServer = KeywordSearch.getServer();
|
||||||
|
if (solrServer.coreIsOpen() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return solrServer.queryIsIndexed(objectId);
|
return solrServer.queryIsIndexed(objectId);
|
||||||
} catch (NoOpenCoreException | KeywordSearchModuleException ex) {
|
} catch (NoOpenCoreException | KeywordSearchModuleException ex) {
|
||||||
|
@ -227,7 +227,7 @@ class Ingester {
|
|||||||
solrServer.addDocument(updateDoc);
|
solrServer.addDocument(updateDoc);
|
||||||
uncommitedIngests = true;
|
uncommitedIngests = true;
|
||||||
|
|
||||||
} catch (KeywordSearchModuleException ex) {
|
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
|
||||||
//JMTODO: does this need to be internationalized?
|
//JMTODO: does this need to be internationalized?
|
||||||
throw new IngesterException(
|
throw new IngesterException(
|
||||||
NbBundle.getMessage(Ingester.class, "Ingester.ingest.exception.err.msg", sourceName), ex);
|
NbBundle.getMessage(Ingester.class, "Ingester.ingest.exception.err.msg", sourceName), ex);
|
||||||
|
@ -42,8 +42,9 @@ public class KeywordSearch {
|
|||||||
private static final Logger TIKA_LOGGER = Logger.getLogger("Tika"); //NON-NLS
|
private static final Logger TIKA_LOGGER = Logger.getLogger("Tika"); //NON-NLS
|
||||||
private static final org.sleuthkit.autopsy.coreutils.Logger logger = org.sleuthkit.autopsy.coreutils.Logger.getLogger(Case.class.getName());
|
private static final org.sleuthkit.autopsy.coreutils.Logger logger = org.sleuthkit.autopsy.coreutils.Logger.getLogger(Case.class.getName());
|
||||||
|
|
||||||
|
// @@@ We should move this into TskData (or somewhere) because we are using
|
||||||
|
// this value in the results tree to display substring differently from regexp (KeywordHit.java)
|
||||||
public enum QueryType {
|
public enum QueryType {
|
||||||
|
|
||||||
LITERAL, SUBSTRING, REGEX
|
LITERAL, SUBSTRING, REGEX
|
||||||
};
|
};
|
||||||
public static final String NUM_FILES_CHANGE_EVT = "NUM_FILES_CHANGE_EVT"; //NON-NLS
|
public static final String NUM_FILES_CHANGE_EVT = "NUM_FILES_CHANGE_EVT"; //NON-NLS
|
||||||
|
@ -166,7 +166,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
|||||||
if (!IndexFinder.getCurrentSchemaVersion().equals(indexInfo.getSchemaVersion())) {
|
if (!IndexFinder.getCurrentSchemaVersion().equals(indexInfo.getSchemaVersion())) {
|
||||||
throw new IngestModuleException(Bundle.KeywordSearchIngestModule_startupException_indexSchemaNotSupported(indexInfo.getSchemaVersion()));
|
throw new IngestModuleException(Bundle.KeywordSearchIngestModule_startupException_indexSchemaNotSupported(indexInfo.getSchemaVersion()));
|
||||||
}
|
}
|
||||||
} catch (KeywordSearchModuleException ex) {
|
} catch (NoOpenCoreException ex) {
|
||||||
throw new IngestModuleException(Bundle.KeywordSearchIngestModule_startupMessage_failedToGetIndexSchema(), ex);
|
throw new IngestModuleException(Bundle.KeywordSearchIngestModule_startupMessage_failedToGetIndexSchema(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,22 +55,7 @@ class KeywordSearchQueryDelegator {
|
|||||||
|
|
||||||
for (KeywordList keywordList : keywordLists) {
|
for (KeywordList keywordList : keywordLists) {
|
||||||
for (Keyword keyword : keywordList.getKeywords()) {
|
for (Keyword keyword : keywordList.getKeywords()) {
|
||||||
KeywordSearchQuery query;
|
KeywordSearchQuery query = KeywordSearchUtil.getQueryForKeyword(keyword, keywordList);
|
||||||
if (keyword.searchTermIsLiteral()) {
|
|
||||||
// literal, exact match
|
|
||||||
if (keyword.searchTermIsWholeWord()) {
|
|
||||||
query = new LuceneQuery(keywordList, keyword);
|
|
||||||
query.escape();
|
|
||||||
} // literal, substring match
|
|
||||||
else {
|
|
||||||
query = new TermsComponentQuery(keywordList, keyword);
|
|
||||||
query.escape();
|
|
||||||
query.setSubstringQuery();
|
|
||||||
}
|
|
||||||
} // regexp
|
|
||||||
else {
|
|
||||||
query = new RegexQuery(keywordList, keyword);
|
|
||||||
}
|
|
||||||
queryDelegates.add(query);
|
queryDelegates.add(query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,26 @@ class KeywordSearchUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static KeywordSearchQuery getQueryForKeyword(Keyword keyword, KeywordList keywordList) {
|
||||||
|
KeywordSearchQuery query = null;
|
||||||
|
if (keyword.searchTermIsLiteral()) {
|
||||||
|
// literal, exact match
|
||||||
|
if (keyword.searchTermIsWholeWord()) {
|
||||||
|
query = new LuceneQuery(keywordList, keyword);
|
||||||
|
query.escape();
|
||||||
|
} // literal, substring match
|
||||||
|
else {
|
||||||
|
query = new TermsComponentQuery(keywordList, keyword);
|
||||||
|
query.escape();
|
||||||
|
query.setSubstringQuery();
|
||||||
|
}
|
||||||
|
} // regexp
|
||||||
|
else {
|
||||||
|
query = new RegexQuery(keywordList, keyword);
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the Keyword Search list at absPath an XML list?
|
* Is the Keyword Search list at absPath an XML list?
|
||||||
|
@ -370,7 +370,7 @@ public final class SearchRunner {
|
|||||||
private List<Keyword> keywords; //keywords to search
|
private List<Keyword> keywords; //keywords to search
|
||||||
private List<String> keywordListNames; // lists currently being searched
|
private List<String> keywordListNames; // lists currently being searched
|
||||||
private List<KeywordList> keywordLists;
|
private List<KeywordList> keywordLists;
|
||||||
private Map<String, KeywordList> keywordToList; //keyword to list name mapping
|
private Map<Keyword, KeywordList> keywordToList; //keyword to list name mapping
|
||||||
private AggregateProgressHandle progressGroup;
|
private AggregateProgressHandle progressGroup;
|
||||||
private final Logger logger = Logger.getLogger(SearchRunner.Searcher.class.getName());
|
private final Logger logger = Logger.getLogger(SearchRunner.Searcher.class.getName());
|
||||||
private boolean finalRun = false;
|
private boolean finalRun = false;
|
||||||
@ -425,14 +425,13 @@ public final class SearchRunner {
|
|||||||
|
|
||||||
int keywordsSearched = 0;
|
int keywordsSearched = 0;
|
||||||
|
|
||||||
for (Keyword keywordQuery : keywords) {
|
for (Keyword keyword : keywords) {
|
||||||
if (this.isCancelled()) {
|
if (this.isCancelled()) {
|
||||||
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: {0}", keywordQuery.getSearchTerm()); //NON-NLS
|
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: {0}", keyword.getSearchTerm()); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String queryStr = keywordQuery.getSearchTerm();
|
final KeywordList keywordList = keywordToList.get(keyword);
|
||||||
final KeywordList list = keywordToList.get(queryStr);
|
|
||||||
|
|
||||||
//new subProgress will be active after the initial query
|
//new subProgress will be active after the initial query
|
||||||
//when we know number of hits to start() with
|
//when we know number of hits to start() with
|
||||||
@ -440,15 +439,7 @@ public final class SearchRunner {
|
|||||||
subProgresses[keywordsSearched - 1].finish();
|
subProgresses[keywordsSearched - 1].finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
KeywordSearchQuery keywordSearchQuery = null;
|
KeywordSearchQuery keywordSearchQuery = KeywordSearchUtil.getQueryForKeyword(keyword, keywordList);
|
||||||
|
|
||||||
boolean isRegex = !keywordQuery.searchTermIsLiteral();
|
|
||||||
if (isRegex) {
|
|
||||||
keywordSearchQuery = new RegexQuery(list, keywordQuery);
|
|
||||||
} else {
|
|
||||||
keywordSearchQuery = new LuceneQuery(list, keywordQuery);
|
|
||||||
keywordSearchQuery.escape();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filtering
|
// Filtering
|
||||||
//limit search to currently ingested data sources
|
//limit search to currently ingested data sources
|
||||||
@ -462,14 +453,14 @@ public final class SearchRunner {
|
|||||||
try {
|
try {
|
||||||
queryResults = keywordSearchQuery.performQuery();
|
queryResults = keywordSearchQuery.performQuery();
|
||||||
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
|
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Error performing query: " + keywordQuery.getSearchTerm(), ex); //NON-NLS
|
logger.log(Level.SEVERE, "Error performing query: " + keyword.getSearchTerm(), ex); //NON-NLS
|
||||||
MessageNotifyUtil.Notify.error(Bundle.SearchRunner_query_exception_msg() + keywordQuery.getSearchTerm(), ex.getCause().getMessage());
|
MessageNotifyUtil.Notify.error(Bundle.SearchRunner_query_exception_msg() + keyword.getSearchTerm(), ex.getCause().getMessage());
|
||||||
//no reason to continue with next query if recovery failed
|
//no reason to continue with next query if recovery failed
|
||||||
//or wait for recovery to kick in and run again later
|
//or wait for recovery to kick in and run again later
|
||||||
//likely case has closed and threads are being interrupted
|
//likely case has closed and threads are being interrupted
|
||||||
return null;
|
return null;
|
||||||
} catch (CancellationException e) {
|
} catch (CancellationException e) {
|
||||||
logger.log(Level.INFO, "Cancel detected, bailing during keyword query: {0}", keywordQuery.getSearchTerm()); //NON-NLS
|
logger.log(Level.INFO, "Cancel detected, bailing during keyword query: {0}", keyword.getSearchTerm()); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,14 +478,14 @@ public final class SearchRunner {
|
|||||||
int totalUnits = newResults.getKeywords().size();
|
int totalUnits = newResults.getKeywords().size();
|
||||||
subProgresses[keywordsSearched].start(totalUnits);
|
subProgresses[keywordsSearched].start(totalUnits);
|
||||||
int unitProgress = 0;
|
int unitProgress = 0;
|
||||||
String queryDisplayStr = keywordQuery.getSearchTerm();
|
String queryDisplayStr = keyword.getSearchTerm();
|
||||||
if (queryDisplayStr.length() > 50) {
|
if (queryDisplayStr.length() > 50) {
|
||||||
queryDisplayStr = queryDisplayStr.substring(0, 49) + "...";
|
queryDisplayStr = queryDisplayStr.substring(0, 49) + "...";
|
||||||
}
|
}
|
||||||
subProgresses[keywordsSearched].progress(list.getName() + ": " + queryDisplayStr, unitProgress);
|
subProgresses[keywordsSearched].progress(keywordList.getName() + ": " + queryDisplayStr, unitProgress);
|
||||||
|
|
||||||
// Create blackboard artifacts
|
// Create blackboard artifacts
|
||||||
newArtifacts = newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, list.getIngestMessages());
|
newArtifacts = newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages());
|
||||||
|
|
||||||
} //if has results
|
} //if has results
|
||||||
|
|
||||||
@ -553,7 +544,7 @@ public final class SearchRunner {
|
|||||||
keywordLists.add(list);
|
keywordLists.add(list);
|
||||||
for (Keyword k : list.getKeywords()) {
|
for (Keyword k : list.getKeywords()) {
|
||||||
keywords.add(k);
|
keywords.add(k);
|
||||||
keywordToList.put(k.getSearchTerm(), list);
|
keywordToList.put(k, list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,9 @@ import java.nio.charset.Charset;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -62,11 +60,9 @@ import org.apache.solr.common.SolrInputDocument;
|
|||||||
import org.apache.solr.common.util.NamedList;
|
import org.apache.solr.common.util.NamedList;
|
||||||
import org.openide.modules.InstalledFileLocator;
|
import org.openide.modules.InstalledFileLocator;
|
||||||
import org.openide.modules.Places;
|
import org.openide.modules.Places;
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
||||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
@ -241,7 +237,7 @@ public class Server {
|
|||||||
javaHome = System.getenv("JAVA_HOME"); // NON-NLS
|
javaHome = System.getenv("JAVA_HOME"); // NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
if (javaHome.isEmpty()) {
|
if (javaHome == null || javaHome.isEmpty()) {
|
||||||
logger.log(Level.WARNING, "Java not found. Keyword search functionality may not work."); //NON-NLS
|
logger.log(Level.WARNING, "Java not found. Keyword search functionality may not work."); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,17 +692,16 @@ public class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Index getIndexInfo() throws KeywordSearchModuleException {
|
Index getIndexInfo() throws NoOpenCoreException {
|
||||||
currentCoreLock.readLock().lock();
|
currentCoreLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
if (null != currentCore) {
|
if (null == currentCore) {
|
||||||
return currentCore.getIndexInfo();
|
throw new NoOpenCoreException();
|
||||||
} else {
|
|
||||||
throw new KeywordSearchModuleException("Cannot get text index info, no core is open");
|
|
||||||
}
|
}
|
||||||
|
return currentCore.getIndexInfo();
|
||||||
} finally {
|
} finally {
|
||||||
currentCoreLock.readLock().unlock();
|
currentCoreLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeCore() throws KeywordSearchModuleException {
|
void closeCore() throws KeywordSearchModuleException {
|
||||||
@ -722,9 +717,12 @@ public class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addDocument(SolrInputDocument doc) throws KeywordSearchModuleException {
|
void addDocument(SolrInputDocument doc) throws KeywordSearchModuleException, NoOpenCoreException {
|
||||||
currentCoreLock.readLock().lock();
|
currentCoreLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
|
if (null == currentCore) {
|
||||||
|
throw new NoOpenCoreException();
|
||||||
|
}
|
||||||
currentCore.addDocument(doc);
|
currentCore.addDocument(doc);
|
||||||
} finally {
|
} finally {
|
||||||
currentCoreLock.readLock().unlock();
|
currentCoreLock.readLock().unlock();
|
||||||
|
@ -179,7 +179,7 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService {
|
|||||||
"SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
|
"SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
|
||||||
"SolrSearch.indentifyingIndex.msg=Identifying text index for upgrade",
|
"SolrSearch.indentifyingIndex.msg=Identifying text index for upgrade",
|
||||||
"SolrSearch.copyIndex.msg=Copying existing text index",
|
"SolrSearch.copyIndex.msg=Copying existing text index",
|
||||||
"SolrSearch.openCore.msg=Creating/Opening text index",
|
"SolrSearch.openCore.msg=Opening text index",
|
||||||
"SolrSearch.complete.msg=Text index successfully opened"})
|
"SolrSearch.complete.msg=Text index successfully opened"})
|
||||||
public void openCaseResources(CaseContext context) throws AutopsyServiceException {
|
public void openCaseResources(CaseContext context) throws AutopsyServiceException {
|
||||||
ProgressIndicator progress = context.getProgressIndicator();
|
ProgressIndicator progress = context.getProgressIndicator();
|
||||||
|
@ -347,6 +347,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
|||||||
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import junit.framework.Test;
|
|||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import org.netbeans.jemmy.Timeouts;
|
import org.netbeans.jemmy.Timeouts;
|
||||||
import org.netbeans.junit.NbModuleSuite;
|
import org.netbeans.junit.NbModuleSuite;
|
||||||
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test expects the following system properties to be set: img_path: The
|
* This test expects the following system properties to be set: img_path: The
|
||||||
@ -98,6 +99,7 @@ public class RegressionTest extends TestCase {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
logger.info("######## " + AutopsyTestCases.getEscapedPath(System.getProperty("img_path")) + " #######");
|
logger.info("######## " + AutopsyTestCases.getEscapedPath(System.getProperty("img_path")) + " #######");
|
||||||
Timeouts.setDefault("ComponentOperator.WaitComponentTimeout", 1000000);
|
Timeouts.setDefault("ComponentOperator.WaitComponentTimeout", 1000000);
|
||||||
|
UserPreferences.setNumberOfFileIngestThreads(1); //Let nightly test using 1 ingest thread to avoid ordering results in report of insertion to tsk tables
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
0
thunderbirdparser/release/modules/ext/java-libpst-1.0-SNAPSHOT.jar → thirdparty/java-libpst/java-libpst-1.0-SNAPSHOT.jar
vendored
Executable file → Normal file
@ -2,7 +2,61 @@
|
|||||||
<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
|
<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
|
||||||
<!-- for some information on what you could do (e.g. targets to override). -->
|
<!-- for some information on what you could do (e.g. targets to override). -->
|
||||||
<!-- If you delete this file and reopen the project it will be recreated. -->
|
<!-- If you delete this file and reopen the project it will be recreated. -->
|
||||||
<project name="org.sleuthkit.autopsy.thunderbirdparser" default="netbeans" basedir=".">
|
<project name="org.sleuthkit.autopsy.thunderbirdparser" default="netbeans" basedir="." xmlns:ivy="antlib:org.apache.ivy.ant">
|
||||||
<description>Builds, tests, and runs the project org.sleuthkit.autopsy.thunderbirdparser.</description>
|
<description>Builds, tests, and runs the project org.sleuthkit.autopsy.thunderbirdparser.</description>
|
||||||
<import file="nbproject/build-impl.xml"/>
|
<import file="nbproject/build-impl.xml"/>
|
||||||
|
|
||||||
|
|
||||||
|
<property name="ivy.install.version" value="2.3.0-rc2" />
|
||||||
|
<condition property="ivy.home" value="${env.IVY_HOME}">
|
||||||
|
<isset property="env.IVY_HOME" />
|
||||||
|
</condition>
|
||||||
|
<property name="ivy.home" value="${user.home}/.ant" />
|
||||||
|
<property name="ivy.jar.dir" value="${ivy.home}/lib" />
|
||||||
|
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
|
||||||
|
|
||||||
|
<target name="download-ivy" unless="offline">
|
||||||
|
<available file="${ivy.jar.file}" property="ivy.available"/>
|
||||||
|
<antcall target="-download-ivy" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="-download-ivy" unless="ivy.available">
|
||||||
|
<mkdir dir="${ivy.jar.dir}"/>
|
||||||
|
<get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
|
||||||
|
dest="${ivy.jar.file}" usetimestamp="true"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- init-ivy will bootstrap Ivy if the user doesn't have it already -->
|
||||||
|
<target name="init-ivy" depends="download-ivy" unless="ivy.lib.path">
|
||||||
|
<path id="ivy.lib.path">
|
||||||
|
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
|
||||||
|
</path>
|
||||||
|
<taskdef resource="org/apache/ivy/ant/antlib.xml"
|
||||||
|
uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
|
||||||
|
<property name="thirdparty.dir" value="${basedir}/../thirdparty" />
|
||||||
|
<property name="ext.dir" value="release/modules/ext" />
|
||||||
|
|
||||||
|
<target name="clean" depends="projectized-common.clean">
|
||||||
|
<delete dir="${ext.dir}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="get-thirdparty-jars" description="get third-party jar dependencies">
|
||||||
|
<mkdir dir="${ext.dir}"/>
|
||||||
|
<copy file="${thirdparty.dir}/java-libpst/java-libpst-1.0-SNAPSHOT.jar" todir="${ext.dir}" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="init" depends="basic-init,files-init,build-init,-javac-init,init-ivy">
|
||||||
|
<!-- fetch all the dependencies from Ivy and stick them in the right places -->
|
||||||
|
<ivy:resolve/>
|
||||||
|
<ivy:retrieve conf="autopsy" sync="true" pattern="release/modules/ext/[artifact]-[revision](-[classifier]).[ext]" />
|
||||||
|
|
||||||
|
<!-- copy jars not downloaded with Ivy -->
|
||||||
|
<antcall target="get-thirdparty-jars"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
||||||
|
14
thunderbirdparser/ivy.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
<ivy-module version="2.0">
|
||||||
|
<info organisation="org.sleuthkit.autopsy" module="emailparser"/>
|
||||||
|
<configurations >
|
||||||
|
<!-- module dependencies -->
|
||||||
|
<conf name="autopsy"/>
|
||||||
|
|
||||||
|
</configurations>
|
||||||
|
<dependencies>
|
||||||
|
<dependency conf="autopsy->default" org="org.apache.james" name="apache-mime4j-core" rev="0.8.0"/>
|
||||||
|
<dependency conf="autopsy->default" org="org.apache.james" name="apache-mime4j-dom" rev="0.8.0"/>
|
||||||
|
<dependency conf="autopsy->default" org="org.apache.james" name="apache-mime4j-mbox-iterator" rev="0.8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
</ivy-module>
|
9
thunderbirdparser/ivysettings.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<ivysettings>
|
||||||
|
<settings defaultResolver="main"/>
|
||||||
|
<resolvers>
|
||||||
|
<chain name="main">
|
||||||
|
<ibiblio name="central" m2compatible="true"/>
|
||||||
|
<ibiblio name="maven.restlet.org" root="http://maven.restlet.com" m2compatible="true" />
|
||||||
|
</chain>
|
||||||
|
</resolvers>
|
||||||
|
</ivysettings>
|
@ -1,7 +1,6 @@
|
|||||||
file.reference.apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar=release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar
|
file.reference.apache-mime4j-core-0.8.0.jar=release/modules/ext/apache-mime4j-core-0.8.0.jar
|
||||||
file.reference.apache-mime4j-core-0.8.0-SNAPSHOT.jar=release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar
|
file.reference.apache-mime4j-dom-0.8.0.jar=release/modules/ext/apache-mime4j-dom-0.8.0.jar
|
||||||
file.reference.apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar=release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar
|
file.reference.apache-mime4j-mbox-iterator-0.8.0.jar=release/modules/ext/apache-mime4j-mbox-iterator-0.8.0.jar
|
||||||
file.reference.apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar=release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar
|
|
||||||
file.reference.java-libpst-1.0-SNAPSHOT.jar=release/modules/ext/java-libpst-1.0-SNAPSHOT.jar
|
file.reference.java-libpst-1.0-SNAPSHOT.jar=release/modules/ext/java-libpst-1.0-SNAPSHOT.jar
|
||||||
javac.source=1.8
|
javac.source=1.8
|
||||||
javac.compilerargs=-Xlint -Xlint:-serial
|
javac.compilerargs=-Xlint -Xlint:-serial
|
||||||
|
@ -51,32 +51,20 @@
|
|||||||
</module-dependencies>
|
</module-dependencies>
|
||||||
<public-packages/>
|
<public-packages/>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/apache-mime4j-dom-0.8.0-SNAPSHOT-sources.jar</runtime-relative-path>
|
<runtime-relative-path>ext/apache-mime4j-core-0.8.0.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT-sources.jar</binary-origin>
|
<binary-origin>release/modules/ext/apache-mime4j-core-0.8.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar</runtime-relative-path>
|
<runtime-relative-path>ext/apache-mime4j-dom-0.8.0.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar</binary-origin>
|
<binary-origin>release/modules/ext/apache-mime4j-dom-0.8.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
|
||||||
<class-path-extension>
|
|
||||||
<runtime-relative-path>ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar</runtime-relative-path>
|
|
||||||
<binary-origin>release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar</binary-origin>
|
|
||||||
</class-path-extension>
|
|
||||||
<class-path-extension>
|
|
||||||
<runtime-relative-path>ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar</runtime-relative-path>
|
|
||||||
<binary-origin>release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar</binary-origin>
|
|
||||||
</class-path-extension>
|
|
||||||
<class-path-extension>
|
|
||||||
<runtime-relative-path>ext/apache-mime4j-dom-0.8.0-SNAPSHOT.jar</runtime-relative-path>
|
|
||||||
<binary-origin>release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT.jar</binary-origin>
|
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/java-libpst-1.0-SNAPSHOT.jar</runtime-relative-path>
|
<runtime-relative-path>ext/java-libpst-1.0-SNAPSHOT.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/java-libpst-1.0-SNAPSHOT.jar</binary-origin>
|
<binary-origin>release/modules/ext/java-libpst-1.0-SNAPSHOT.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar</runtime-relative-path>
|
<runtime-relative-path>ext/apache-mime4j-mbox-iterator-0.8.0.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar</binary-origin>
|
<binary-origin>release/modules/ext/apache-mime4j-mbox-iterator-0.8.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
</data>
|
</data>
|
||||||
</configuration>
|
</configuration>
|
||||||
|