diff --git a/.gitignore b/.gitignore
index 5e4866a207..dc88052299 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,3 +77,5 @@ Core/src/org/sleuthkit/autopsy/casemodule/docs/screenshot.png
.DS_Store
.*.swp
Core/src/org/sleuthkit/autopsy/datamodel/ranges.csv
+
+thunderbirdparser/release/modules/ext
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectDspVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectDspVisual.java
index dea544c416..9c66184b47 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectDspVisual.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectDspVisual.java
@@ -37,6 +37,7 @@ import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;
import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.datasourceprocessors.RawDSProcessor;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -56,8 +57,11 @@ final class AddImageWizardSelectDspVisual extends JPanel {
AddImageWizardSelectDspVisual(String lastDspUsed) {
initComponents();
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();
-
//add actionlistner to listen for change
}
@@ -87,6 +91,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
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
* option.
@@ -110,6 +115,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
constraints.anchor = GridBagConstraints.LINE_START;
Dimension spacerBlockDimension = new Dimension(6, 4); // Space between left edge and button, Space between rows
for (String dspType : dspList) {
+ boolean shouldAddMultiUserWarning = false;
constraints.weightx = 1;
//Add a spacer
Filler spacer = new Filler(spacerBlockDimension, spacerBlockDimension, spacerBlockDimension);
@@ -120,6 +126,11 @@ final class AddImageWizardSelectDspVisual extends JPanel {
//Add the button
JToggleButton dspButton = createDspButton(dspType);
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);
buttonGroup1.add(dspButton);
gridBagLayout.setConstraints(dspButton, constraints);
@@ -130,7 +141,14 @@ final class AddImageWizardSelectDspVisual extends JPanel {
jPanel1.add(buttonTextSpacer);
constraints.gridx++;
//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.setEditable(false);
myLabel.setWrapStyleWord(true);
@@ -169,12 +187,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
}
}
dspList.add(ImageDSProcessor.getType());
- if (Case.getCurrentCase().getCaseType() != Case.CaseType.MULTI_USER_CASE) {
- dspList.add(LocalDiskDSProcessor.getType());
- } else {
- // remove LocalDiskDSProcessor from list of DSPs
- datasourceProcessorsMap.remove(LocalDiskDSProcessor.getType());
- }
+ dspList.add(LocalDiskDSProcessor.getType());
dspList.add(LocalFilesDSProcessor.getType());
dspList.add(RawDSProcessor.getType());
// now add any addtional DSPs that haven't already been added
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties
index 05c2693128..05588f5d1f 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties
@@ -140,8 +140,8 @@ CasePropertiesForm.updateCaseName.msgDlg.empty.msg=The caseName cannot be empty.
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.title=Error
-CasePropertiesForm.updateCaseName.confMsg.msg=Are you sure want to update the case name from "{0}" to "{1}"?
-CasePropertiesForm.updateCaseName.confMsg.title=Create directory
+CasePropertiesForm.updateCaseName.confMsg.msg=Are you sure you want to update the case name from "{0}" to "{1}"?
+CasePropertiesForm.updateCaseName.confMsg.title=Change Case Name
CueBannerPanel.title.text=Open Recent Case
GeneralFilter.rawImageDesc.text=Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin)
GeneralFilter.encaseImageDesc.text=Encase Images (*.e01)
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties
index 82efd7df67..68605bb1b8 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties
@@ -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.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.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
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)
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
index e3ab78bf64..5facca3088 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
@@ -568,7 +568,8 @@ public class Case {
*
* IMPORTANT: This method should not be called in the event dispatch thread
* (EDT).
- * @throws CaseActionException
+ *
+ * @throws CaseActionException
*/
@Messages({
"# {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}",
"Case.progressIndicatorTitle.deletingCase=Deleting Case",
"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.deletingCaseDatabase=Deleting case database...",
"Case.exceptionMessage.cancelled=Cancelled by user"
@@ -672,7 +674,7 @@ public class Case {
* First, acquire an exclusive case directory lock. The case
* 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())) {
assert (null != dirLock);
@@ -723,8 +725,9 @@ public class Case {
}
/**
- * Sanitizes the case name for use as a PostgreSQL database name and in
- * ActiveMQ event channel (topic) names.
+ * Cleans up the display name for a case to make a suitable case name for
+ * use in case direcotry paths, coordination service locks, PostgreSQL
+ * database names, Active MQ message message channels, etc.
*
* PostgreSQL:
* 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
*/
- static String sanitizeCaseName(String caseName) throws IllegalCaseNameException {
+ public static String displayNameToCaseName(String caseName) throws IllegalCaseNameException {
String result;
@@ -1604,7 +1607,7 @@ public class Case {
"Case.progressIndicatorTitle.creatingCase=Creating Case",
"Case.progressIndicatorCancelButton.label=Cancel",
"Case.progressMessage.preparing=Preparing...",
- "Case.progressMessage.acquiringLocks=Preparing to open case resources.
This may take time if another user is upgrading the case."
+ "Case.progressMessage.openingCaseResources=Preparing to open case resources.
This may take time if another user is upgrading the case."
})
private void open(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException {
/*
@@ -1613,7 +1616,7 @@ public class Case {
*/
String caseName;
try {
- caseName = sanitizeCaseName(caseDisplayName);
+ caseName = displayNameToCaseName(caseDisplayName);
} catch (IllegalCaseNameException 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
* 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)) {
assert (null != nameLock);
/*
@@ -1872,7 +1875,7 @@ public class Case {
* as long as this node has this case open, in order to prevent
* deletion of the case by another node.
*/
- progressIndicator.start(Bundle.Case_progressMessage_acquiringLocks());
+ progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources());
acquireSharedCaseDirLock(caseMetadata.getCaseDirectory());
/*
* Next, acquire an exclusive case resources lock to ensure only
@@ -2131,6 +2134,7 @@ public class Case {
* @param progressIndicator A progress indicator.
*/
@Messages({
+ "Case.progressMessage.closingCaseResources=Preparing to close case resources.
This may take time if another user is upgrading the case.",
"Case.progressMessage.notifyingCaseEventSubscribers=Notifying case event subscribers...",
"Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
"Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
@@ -2139,7 +2143,6 @@ public class Case {
"Case.progressMessage.closingCaseDatabase=Closing case database...",
"Case.progressMessage.tearingDownTskErrorReporting=Tearing down SleuthKit error reporting..."
})
-
private void close() throws CaseActionException {
/*
* 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
* resources.
*/
- progressIndicator.start(Bundle.Case_progressMessage_acquiringLocks());
+ progressIndicator.start(Bundle.Case_progressMessage_closingCaseResources());
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseMetadata.getCaseName())) {
assert (null != resourcesLock);
close(progressIndicator);
@@ -2406,7 +2409,7 @@ public class Case {
* An exception to throw when a case name with invalid characters is
* encountered.
*/
- final static class IllegalCaseNameException extends Exception {
+ public final static class IllegalCaseNameException extends Exception {
private static final long serialVersionUID = 1L;
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java
index 737cbe8839..8ceda8fc2a 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java
@@ -204,17 +204,27 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel |
- if (!Case.isValidName(caseName)) {
+ if (!Case.isValidName(caseDisplayName)) {
String errorMsg = NbBundle
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.invalidSymbols");
validationError(errorMsg);
} 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
if (new File(caseDirPath).exists()) {
// throw a warning to enter new data or delete the existing directory
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java
index 6d57f3daac..ddc0ccd1d5 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java
@@ -177,7 +177,7 @@ public class SingleUserCaseConverter {
// Create sanitized names for PostgreSQL and Solr
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); //NON-NLS
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);
// Copy items to new hostname folder structure
diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java
index b80642ee43..19933f8247 100755
--- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java
+++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java
@@ -137,6 +137,8 @@ public class ImageUtils {
OPEN_CV_LOADED = openCVLoadedTemp;
SUPPORTED_IMAGE_EXTENSIONS.addAll(Arrays.asList(ImageIO.getReaderFileSuffixes()));
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()));
/*
* special cases and variants that we support, but don't get registered
@@ -160,7 +162,7 @@ public class ImageUtils {
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
= Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
@@ -297,12 +299,27 @@ public class ImageUtils {
* @param content the content to generate a thumbnail for
* @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.
*/
public static BufferedImage getThumbnail(Content content, int iconSize) {
if (content instanceof AbstractFile) {
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 thumbnailTask = newGetThumbnailTask(file, iconSize, true);
thumbnailTask.run();
@@ -310,11 +327,22 @@ public class ImageUtils {
return SwingFXUtils.fromFXImage(thumbnailTask.get(), null);
} catch (InterruptedException | ExecutionException ex) {
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
- * as a java File. The returned File may not exist on disk yet.
+ * Get the location,as a java File, of the cached thumbnail for an file with
+ * the given fileID . The returned File may not exist on disk yet.
*
* @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
* any problem getting the file, such as no case was open.
*/
@@ -542,33 +570,30 @@ public class ImageUtils {
* @see #getImageHeight(org.sleuthkit.datamodel.AbstractFile)
*/
private static T getImageProperty(AbstractFile file, final String errorTemplate, PropertyExtractor propertyExtractor) throws IOException {
- try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) {
- try (ImageInputStream input = ImageIO.createImageInputStream(inputStream)) {
- if (input == null) {
- IIOException iioException = new IIOException("Could not create ImageInputStream.");
- LOGGER.log(Level.WARNING, errorTemplate + iioException.toString(), getContentPathSafe(file));
- throw iioException;
- }
- Iterator readers = ImageIO.getImageReaders(input);
-
- if (readers.hasNext()) {
- ImageReader reader = readers.next();
- reader.setInput(input);
- try {
-
- return propertyExtractor.extract(reader);
- } catch (IOException ex) {
- LOGGER.log(Level.WARNING, errorTemplate + ex.toString(), getContentPathSafe(file));
- throw ex;
- } finally {
- reader.dispose();
- }
- } else {
- IIOException iioException = new IIOException("No ImageReader found.");
- LOGGER.log(Level.WARNING, errorTemplate + iioException.toString(), getContentPathSafe(file));
-
- throw iioException;
+ try (InputStream inputStream = getBufferedReadContentStream(file);
+ ImageInputStream input = ImageIO.createImageInputStream(inputStream)) {
+ if (input == null) {
+ IIOException iioException = new IIOException("Could not create ImageInputStream.");
+ LOGGER.log(Level.WARNING, errorTemplate + iioException.toString(), getContentPathSafe(file));
+ throw iioException;
+ }
+ Iterator readers = ImageIO.getImageReaders(input);
+
+ if (readers.hasNext()) {
+ ImageReader reader = readers.next();
+ reader.setInput(input);
+ try {
+ return propertyExtractor.extract(reader);
+ } catch (IOException ex) {
+ LOGGER.log(Level.WARNING, errorTemplate + ex.toString(), getContentPathSafe(file));
+ throw ex;
+ } finally {
+ reader.dispose();
}
+ } 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 {
if (ImageUtils.isGIF(file)) {
//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) {
return image;
}
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java
index 2b9fb9f2b8..972951ea99 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java
@@ -90,6 +90,8 @@ public interface DisplayableItemNodeVisitor {
T visit(KeywordHits.ListNode khsn);
T visit(KeywordHits.TermNode khmln);
+
+ T visit(KeywordHits.RegExpInstanceNode khmln);
T visit(HashsetHits.RootNode hhrn);
@@ -280,6 +282,11 @@ public interface DisplayableItemNodeVisitor {
public T visit(KeywordHits.ListNode khsn) {
return defaultVisit(khsn);
}
+
+ @Override
+ public T visit(KeywordHits.RegExpInstanceNode khsn) {
+ return defaultVisit(khsn);
+ }
@Override
public T visit(KeywordHits.TermNode khmln) {
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java
index c7b8983be0..72746663e7 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java
@@ -64,17 +64,24 @@ public class KeywordHits implements AutopsyVisitableItem {
public static final String SIMPLE_REGEX_SEARCH = NbBundle
.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
private final KeywordResults keywordResults;
-
+ private final String DUMMY_INSTANCE = "DUMMY_EXACT_MATCH_INSTANCE";
+
public KeywordHits(SleuthkitCase skCase) {
this.skCase = skCase;
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 {
- // 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
- private final Map>> topLevelMap = new LinkedHashMap<>();
+ private final Map>>> topLevelMap = new LinkedHashMap<>();
KeywordResults() {
update();
@@ -98,26 +105,66 @@ public class KeywordHits implements AutopsyVisitableItem {
Collections.sort(keywords);
return keywords;
}
-
- Set getArtifactIds(String listName, String keyword) {
+
+ List getKeywordInstances(String listName, String keyword) {
+ List instances;
synchronized (topLevelMap) {
- return topLevelMap.get(listName).get(keyword);
+ instances = new ArrayList<>(topLevelMap.get(listName).get(keyword).keySet());
+ }
+ Collections.sort(instances);
+ return instances;
+ }
+
+ Set getArtifactIds(String listName, String keyword, String keywordInstance) {
+ synchronized (topLevelMap) {
+ return topLevelMap.get(listName).get(keyword).get(keywordInstance);
}
}
+ void addRegExpToList(Map>> listMap, String regExp, String word, Long id) {
+ if (listMap.containsKey(regExp) == false) {
+ listMap.put(regExp, new LinkedHashMap<>());
+ }
+ Map> 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>> listMap, String word, Long id) {
+ if (listMap.containsKey(word) == false) {
+ listMap.put(word, new LinkedHashMap<>());
+ }
+ Map> 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
void populateMaps(Map> artifactIds) {
synchronized (topLevelMap) {
topLevelMap.clear();
// map of list name to keword to artifact IDs
- Map>> listsMap = new LinkedHashMap<>();
+ Map>>> listsMap = new LinkedHashMap<>();
- // Map from from literal keyword to artifact IDs
- Map> literalMap = new LinkedHashMap<>();
+ // Map from from literal keyword to instances (which will be empty) to artifact IDs
+ Map>> literalMap = new LinkedHashMap<>();
- // Map from regex keyword artifact IDs
- Map> regexMap = new LinkedHashMap<>();
+ // Map from regex keyword artifact to instances to artifact IDs
+ Map>> regexMap = new LinkedHashMap<>();
// top-level nodes
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 word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.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
if (listName != null) {
+ // get or create list entry
if (listsMap.containsKey(listName) == false) {
- listsMap.put(listName, new LinkedHashMap>());
+ listsMap.put(listName, new LinkedHashMap<>());
}
-
- Map> listMap = listsMap.get(listName);
- if (listMap.containsKey(word) == false) {
- listMap.put(word, new HashSet());
+ Map>> listMap = listsMap.get(listName);
+
+ // substring, treated same as exact match
+ // 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
else if (reg != null) {
- if (regexMap.containsKey(reg) == false) {
- regexMap.put(reg, new HashSet());
+ // substring is treated same as exact
+ 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
else {
- if (literalMap.containsKey(word) == false) {
- literalMap.put(word, new HashSet());
- }
- literalMap.get(word).add(id);
- }
- topLevelMap.putAll(listsMap);
+ addExactMatchToList(literalMap, word, id);
+ }
}
+ topLevelMap.putAll(listsMap);
}
setChanged();
@@ -167,35 +227,43 @@ public class KeywordHits implements AutopsyVisitableItem {
@SuppressWarnings("deprecation")
public void update() {
+ // maps Artifact ID to map of attribute types to attribute values
Map> artifactIds = new LinkedHashMap<>();
if (skCase == null) {
return;
}
+ // query attributes table for the ones that we need for the tree
int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int wordId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID();
int regexId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.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.artifact_id=blackboard_artifacts.artifact_id AND " //NON-NLS
+ "blackboard_artifacts.artifact_type_id=" + artId //NON-NLS
+ ") AND (attribute_type_id=" + setId + " 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
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
ResultSet resultSet = dbQuery.getResultSet();
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 typeId = resultSet.getLong("attribute_type_id"); //NON-NLS
if (!artifactIds.containsKey(artifactId)) {
artifactIds.put(artifactId, new LinkedHashMap());
}
- if (!value.equals("")) {
- artifactIds.get(artifactId).put(typeId, value);
+ if (valueStr != null && !valueStr.equals("")) {
+ 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) {
@@ -254,6 +322,9 @@ public class KeywordHits implements AutopsyVisitableItem {
}
}
+ /**
+ * Creates the list nodes
+ */
private class ListFactory extends ChildFactory.Detachable implements Observer {
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 {
private final String listName;
@@ -360,8 +434,10 @@ public class KeywordHits implements AutopsyVisitableItem {
private void updateDisplayName() {
int totalDescendants = 0;
for (String word : keywordResults.getKeywords(listName)) {
- Set ids = keywordResults.getArtifactIds(listName, word);
- totalDescendants += ids.size();
+ for (String instance : keywordResults.getKeywordInstances(listName, word)) {
+ Set ids = keywordResults.getArtifactIds(listName, word, instance);
+ totalDescendants += ids.size();
+ }
}
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 implements Observer {
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 {
private final String setName;
private final 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);
this.setName = setName;
this.keyword = keyword;
@@ -461,7 +543,175 @@ public class KeywordHits implements AutopsyVisitableItem {
}
private void updateDisplayName() {
- super.setDisplayName(keyword + " (" + keywordResults.getArtifactIds(setName, keyword).size() + ")");
+ int totalDescendants = 0;
+
+ for (String instance : keywordResults.getKeywordInstances(setName, keyword)) {
+ Set 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 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 accept(DisplayableItemNodeVisitor 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 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 list) {
+ List 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
@@ -496,7 +746,7 @@ public class KeywordHits implements AutopsyVisitableItem {
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.getArtifactIds(setName, keyword).size()));
+ keywordResults.getKeywordInstances(setName, keyword).size()));
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 implements Observer {
private final String keyword;
private final String setName;
+ private final String instance;
- public HitsFactory(String setName, String keyword) {
+ public HitsFactory(String setName, String keyword, String instance) {
super();
this.setName = setName;
this.keyword = keyword;
+ this.instance = instance;
}
@Override
@@ -530,60 +841,13 @@ public class KeywordHits implements AutopsyVisitableItem {
@Override
protected boolean createKeys(List list) {
- list.addAll(keywordResults.getArtifactIds(setName, keyword));
+ list.addAll(keywordResults.getArtifactIds(setName, keyword, instance));
return true;
}
@Override
protected Node createNodeForKey(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;
+ return createBlackboardArtifactNode(artifactId);
}
@Override
diff --git a/Core/src/org/sleuthkit/autopsy/framework/ProgressPanel.java b/Core/src/org/sleuthkit/autopsy/framework/ProgressPanel.java
index 6d4e46cc42..4957a317b6 100644
--- a/Core/src/org/sleuthkit/autopsy/framework/ProgressPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/framework/ProgressPanel.java
@@ -28,24 +28,25 @@ class ProgressPanel extends javax.swing.JPanel {
ProgressPanel() {
initComponents();
this.progressBar.setMinimum(0);
+ this.progressBar.setIndeterminate(true);
}
void setMessage(String message) {
this.progressMessage.setText(message);
- }
-
+ }
+
void setInderminate(boolean indeterminate) {
this.progressBar.setIndeterminate(indeterminate);
}
-
+
void setMaximum(int max) {
this.progressBar.setMaximum(max);
}
-
+
void setCurrent(int current) {
this.progressBar.setValue(current);
}
-
+
/**
* 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
diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/CallLogAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/CallLogAnalyzer.java
index 8075d8c3fe..27129456e2 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/android/CallLogAnalyzer.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/android/CallLogAnalyzer.java
@@ -25,7 +25,9 @@ import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
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.datamodel.ContentUtils;
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.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@@ -52,6 +56,9 @@ class CallLogAnalyzer {
private static final String moduleName = AndroidModuleFactory.getModuleName();
private static final Logger logger = Logger.getLogger(CallLogAnalyzer.class.getName());
private static Blackboard blackboard;
+
+ private static final IngestServices services = IngestServices.getInstance();
+
/**
* the names of tables that potentially hold call logs in the dbs
@@ -85,6 +92,8 @@ class CallLogAnalyzer {
if (DatabasePath == null || DatabasePath.isEmpty()) {
return;
}
+
+ Collection bbartifacts = new ArrayList<>();
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
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_NAME, moduleName, name));
+ bbartifacts.add(bba);
+
try {
// index the artifact for keyword search
blackboard.indexArtifact(bba);
@@ -131,6 +142,13 @@ class CallLogAnalyzer {
} catch (SQLException e) {
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 {
diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/ContactAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/ContactAnalyzer.java
index 58384f3235..17cc8ad2cc 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/android/ContactAnalyzer.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/android/ContactAnalyzer.java
@@ -25,6 +25,8 @@ import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
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.datamodel.ContentUtils;
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.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@@ -49,6 +53,7 @@ class ContactAnalyzer {
private static final String moduleName = AndroidModuleFactory.getModuleName();
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,
IngestJobContext context) {
@@ -98,7 +103,8 @@ class ContactAnalyzer {
logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS
return;
}
-
+
+ Collection bbartifacts = new ArrayList<>();
try {
// 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.
@@ -152,6 +158,8 @@ class ContactAnalyzer {
}
oldName = name;
+ bbartifacts.add(bba);
+
try {
// index the artifact for keyword search
blackboard.indexArtifact(bba);
@@ -167,6 +175,12 @@ class ContactAnalyzer {
} catch (TskCoreException e) {
logger.log(Level.SEVERE, "Error posting to blackboard", e); //NON-NLS
} finally {
+ if (!bbartifacts.isEmpty()) {
+ services.fireModuleDataEvent(new ModuleDataEvent(
+ moduleName,
+ BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT, bbartifacts));
+ }
+
try {
if (resultSet != null) {
resultSet.close();
diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/TextMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/TextMessageAnalyzer.java
index 2971f07fed..979291d5d3 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/android/TextMessageAnalyzer.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/android/TextMessageAnalyzer.java
@@ -24,6 +24,8 @@ import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
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.datamodel.ContentUtils;
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.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@@ -48,6 +52,7 @@ class TextMessageAnalyzer {
private static final String moduleName = AndroidModuleFactory.getModuleName();
private static final Logger logger = Logger.getLogger(TextMessageAnalyzer.class.getName());
+ private static final IngestServices services = IngestServices.getInstance();
private static Blackboard blackboard;
public static void findTexts(Content dataSource, FileManager fileManager,
@@ -88,6 +93,7 @@ class TextMessageAnalyzer {
return;
}
+ Collection bbartifacts = new ArrayList<>();
try {
resultSet = statement.executeQuery(
"SELECT address,date,read,type,subject,body FROM sms;"); //NON-NLS
@@ -127,6 +133,8 @@ class TextMessageAnalyzer {
NbBundle.getMessage(TextMessageAnalyzer.class,
"TextMessageAnalyzer.bbAttribute.smsMessage")));
+ bbartifacts.add(bba);
+
try {
// index the artifact for keyword search
blackboard.indexArtifact(bba);
@@ -139,6 +147,12 @@ class TextMessageAnalyzer {
} catch (Exception e) {
logger.log(Level.SEVERE, "Error parsing text messages to Blackboard", e); //NON-NLS
} finally {
+ if (!bbartifacts.isEmpty()) {
+ services.fireModuleDataEvent(new ModuleDataEvent(
+ moduleName,
+ BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE, bbartifacts));
+ }
+
try {
if (resultSet != null) {
resultSet.close();
diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java
index 02d3fb82e5..962c18c8e1 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java
@@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TY
*/
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 final String mustBeNamedErrorText;
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java
index 07254c247c..dd370b0534 100644
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java
@@ -68,6 +68,7 @@ import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.Case;
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.CaseMetadata;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
@@ -200,6 +201,12 @@ public final class AutoIngestManager extends Observable implements PropertyChang
casesToManifests = new HashMap<>();
pendingJobs = 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);
jobStatusPublishingExecutor.scheduleAtFixedRate(new PeriodicJobStatusEventTask(), JOB_STATUS_EVENT_INTERVAL_SECONDS, JOB_STATUS_EVENT_INTERVAL_SECONDS, TimeUnit.SECONDS);
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;
errorState = ErrorState.NONE;
}
@@ -1923,17 +1923,23 @@ public final class AutoIngestManager extends Observable implements PropertyChang
*/
private Case openCase() throws CoordinationServiceException, CaseManagementException, InterruptedException {
Manifest manifest = currentJob.getManifest();
- String caseName = manifest.getCaseName();
- SYS_LOGGER.log(Level.INFO, "Opening case {0} for {1}", new Object[]{caseName, manifest.getFilePath()});
+ String caseDisplayName = manifest.getCaseName();
+ 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);
try {
Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, caseName);
if (null != caseDirectoryPath) {
- Path metadataFilePath = caseDirectoryPath.resolve(manifest.getCaseName() + CaseMetadata.getFileExtension());
+ Path metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension());
Case.openAsCurrentCase(metadataFilePath.toString());
} else {
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
* new case folder is visible on the network.
@@ -1946,13 +1952,13 @@ public final class AutoIngestManager extends Observable implements PropertyChang
return caseForJob;
} 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) {
/*
* Deal with the unfortunate fact that Case.getCurrentCase
* 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());
}
} 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});
}
currentJob.setErrorsOccurred(true);
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java
index 852ab4714f..9b99e8c13f 100644
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2015 Basis Technology Corp.
+ * Copyright 2013-2017 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* 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.Collections;
import java.util.List;
+import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
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.
*/
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());
if (!searchFolder.isDirectory()) {
return null;
}
Path caseFolderPath = null;
- String[] candidateFolders = searchFolder.list(new CaseFolderFilter(caseName));
+ String[] candidateFolders = searchFolder.list(new CaseFolderFilter(sanitizedCaseName));
long mostRecentModified = 0;
for (String candidateFolder : candidateFolders) {
File file = new File(candidateFolder);
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java
index f85b5a4050..6e6bcf3d8b 100644
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2013-16 Basis Technology Corp.
+ * Copyright 2011-17 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -182,7 +182,7 @@ public final class ImageGalleryController implements Executor {
return groupManager;
}
- public DrawableDB getDatabase() {
+ synchronized public DrawableDB getDatabase() {
return db;
}
@@ -306,7 +306,7 @@ public final class ImageGalleryController implements Executor {
"ImageGalleryController.noGroupsDlg.msg6=There are no fully analyzed groups to display:"
+ " the current Group By setting resulted in no groups, "
+ "or no groups are fully analyzed but ingest is not running."})
- public void checkForGroups() {
+ synchronized private void checkForGroups() {
if (groupManager.getAnalyzedGroups().isEmpty()) {
if (IngestManager.getInstance().isIngestRunning()) {
if (listeningEnabled.get() == false) {
@@ -951,13 +951,15 @@ public final class ImageGalleryController implements Executor {
if (isListeningEnabled()) {
if (file.isFile()) {
try {
- if (ImageGalleryModule.isDrawableAndNotKnown(file)) {
- //this file should be included and we don't already know about it from hash sets (NSRL)
- queueDBWorkerTask(new UpdateFileTask(file, db));
- } else if (FileTypeUtils.getAllSupportedExtensions().contains(file.getNameExtension())) {
- //doing this check results in fewer tasks queued up, and faster completion of db update
- //this file would have gotten scooped up in initial grab, but actually we don't need it
- queueDBWorkerTask(new RemoveFileTask(file, db));
+ synchronized (ImageGalleryController.this) {
+ if (ImageGalleryModule.isDrawableAndNotKnown(file)) {
+ //this file should be included and we don't already know about it from hash sets (NSRL)
+ queueDBWorkerTask(new UpdateFileTask(file, db));
+ } else if (FileTypeUtils.getAllSupportedExtensions().contains(file.getNameExtension())) {
+ //doing this check results in fewer tasks queued up, and faster completion of db update
+ //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) {
//TODO: What to do here?
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownToolbar.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownToolbar.java
index 2d19342923..3272b9dad1 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownToolbar.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownToolbar.java
@@ -132,7 +132,7 @@ class DropdownToolbar extends javax.swing.JPanel {
}
private void maybeShowListsPopup(MouseEvent evt) {
- if (!active) {
+ if (!active || !listsButton.isEnabled()) {
return;
}
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
@@ -142,7 +142,7 @@ class DropdownToolbar extends javax.swing.JPanel {
}
private void maybeShowSearchPopup(MouseEvent evt) {
- if (!active) {
+ if (!active || !searchDropButton.isEnabled()) {
return;
}
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
@@ -159,41 +159,50 @@ class DropdownToolbar extends javax.swing.JPanel {
String changed = evt.getPropertyName();
if (changed.equals(Case.Events.CURRENT_CASE.toString())) {
if (null != evt.getNewValue()) {
+ boolean disableSearch = false;
/*
* A case has been opened.
*/
try {
Server server = KeywordSearch.getServer();
- Index indexInfo = server.getIndexInfo();
- if (server.coreIsOpen() && 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.
- */
- searchDropButton.setEnabled(false);
- listsButton.setEnabled(false);
- active = false;
+ if (server.coreIsOpen() == false) {
+ disableSearch = true;
}
- } 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.
*/
logger.log(Level.SEVERE, "Error getting text index info", ex); //NON-NLS
+ disableSearch = true;
+ }
+
+ if (disableSearch) {
searchDropButton.setEnabled(false);
listsButton.setEnabled(false);
active = false;
}
+
} else {
/*
* A case has been closed.
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java
index a111bc877a..47c71a8213 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java
@@ -327,6 +327,9 @@ public class ExtractedContentViewer implements DataContentViewer {
*/
private boolean solrHasContent(Long objectId) {
final Server solrServer = KeywordSearch.getServer();
+ if (solrServer.coreIsOpen() == false)
+ return false;
+
try {
return solrServer.queryIsIndexed(objectId);
} catch (NoOpenCoreException | KeywordSearchModuleException ex) {
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
index 9379898051..ad9e151e9e 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java
@@ -227,7 +227,7 @@ class Ingester {
solrServer.addDocument(updateDoc);
uncommitedIngests = true;
- } catch (KeywordSearchModuleException ex) {
+ } catch (KeywordSearchModuleException | NoOpenCoreException ex) {
//JMTODO: does this need to be internationalized?
throw new IngesterException(
NbBundle.getMessage(Ingester.class, "Ingester.ingest.exception.err.msg", sourceName), ex);
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java
index 65fc900569..b09ad5430e 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java
@@ -42,8 +42,9 @@ public class KeywordSearch {
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());
+ // @@@ 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 {
-
LITERAL, SUBSTRING, REGEX
};
public static final String NUM_FILES_CHANGE_EVT = "NUM_FILES_CHANGE_EVT"; //NON-NLS
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java
index 92e186bafe..6f3c11f8cb 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java
@@ -166,7 +166,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
if (!IndexFinder.getCurrentSchemaVersion().equals(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);
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQueryDelegator.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQueryDelegator.java
index af5381ba4b..f2dfb53622 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQueryDelegator.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchQueryDelegator.java
@@ -55,22 +55,7 @@ class KeywordSearchQueryDelegator {
for (KeywordList keywordList : keywordLists) {
for (Keyword keyword : keywordList.getKeywords()) {
- KeywordSearchQuery query;
- 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);
- }
+ KeywordSearchQuery query = KeywordSearchUtil.getQueryForKeyword(keyword, keywordList);
queryDelegates.add(query);
}
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchUtil.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchUtil.java
index bb2a7a4111..cb272811b1 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchUtil.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchUtil.java
@@ -126,6 +126,26 @@ class KeywordSearchUtil {
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?
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SearchRunner.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SearchRunner.java
index ce0d07bc78..6db8b6beb3 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SearchRunner.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SearchRunner.java
@@ -370,7 +370,7 @@ public final class SearchRunner {
private List keywords; //keywords to search
private List keywordListNames; // lists currently being searched
private List keywordLists;
- private Map keywordToList; //keyword to list name mapping
+ private Map keywordToList; //keyword to list name mapping
private AggregateProgressHandle progressGroup;
private final Logger logger = Logger.getLogger(SearchRunner.Searcher.class.getName());
private boolean finalRun = false;
@@ -425,14 +425,13 @@ public final class SearchRunner {
int keywordsSearched = 0;
- for (Keyword keywordQuery : keywords) {
+ for (Keyword keyword : keywords) {
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;
}
- final String queryStr = keywordQuery.getSearchTerm();
- final KeywordList list = keywordToList.get(queryStr);
+ final KeywordList keywordList = keywordToList.get(keyword);
//new subProgress will be active after the initial query
//when we know number of hits to start() with
@@ -440,15 +439,7 @@ public final class SearchRunner {
subProgresses[keywordsSearched - 1].finish();
}
- KeywordSearchQuery keywordSearchQuery = null;
-
- boolean isRegex = !keywordQuery.searchTermIsLiteral();
- if (isRegex) {
- keywordSearchQuery = new RegexQuery(list, keywordQuery);
- } else {
- keywordSearchQuery = new LuceneQuery(list, keywordQuery);
- keywordSearchQuery.escape();
- }
+ KeywordSearchQuery keywordSearchQuery = KeywordSearchUtil.getQueryForKeyword(keyword, keywordList);
// Filtering
//limit search to currently ingested data sources
@@ -462,14 +453,14 @@ public final class SearchRunner {
try {
queryResults = keywordSearchQuery.performQuery();
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
- logger.log(Level.SEVERE, "Error performing query: " + keywordQuery.getSearchTerm(), ex); //NON-NLS
- MessageNotifyUtil.Notify.error(Bundle.SearchRunner_query_exception_msg() + keywordQuery.getSearchTerm(), ex.getCause().getMessage());
+ logger.log(Level.SEVERE, "Error performing query: " + keyword.getSearchTerm(), ex); //NON-NLS
+ MessageNotifyUtil.Notify.error(Bundle.SearchRunner_query_exception_msg() + keyword.getSearchTerm(), ex.getCause().getMessage());
//no reason to continue with next query if recovery failed
//or wait for recovery to kick in and run again later
//likely case has closed and threads are being interrupted
return null;
} 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;
}
@@ -487,14 +478,14 @@ public final class SearchRunner {
int totalUnits = newResults.getKeywords().size();
subProgresses[keywordsSearched].start(totalUnits);
int unitProgress = 0;
- String queryDisplayStr = keywordQuery.getSearchTerm();
+ String queryDisplayStr = keyword.getSearchTerm();
if (queryDisplayStr.length() > 50) {
queryDisplayStr = queryDisplayStr.substring(0, 49) + "...";
}
- subProgresses[keywordsSearched].progress(list.getName() + ": " + queryDisplayStr, unitProgress);
+ subProgresses[keywordsSearched].progress(keywordList.getName() + ": " + queryDisplayStr, unitProgress);
// Create blackboard artifacts
- newArtifacts = newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, list.getIngestMessages());
+ newArtifacts = newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages());
} //if has results
@@ -553,7 +544,7 @@ public final class SearchRunner {
keywordLists.add(list);
for (Keyword k : list.getKeywords()) {
keywords.add(k);
- keywordToList.put(k.getSearchTerm(), list);
+ keywordToList.put(k, list);
}
}
}
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java
index 81b6d5f483..dc3e3b7a28 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java
@@ -36,11 +36,9 @@ import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
@@ -62,11 +60,9 @@ import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.NamedList;
import org.openide.modules.InstalledFileLocator;
import org.openide.modules.Places;
-import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
-import org.sleuthkit.autopsy.casemodule.CaseMetadata;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
@@ -241,7 +237,7 @@ public class Server {
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
}
@@ -696,17 +692,16 @@ public class Server {
}
}
- Index getIndexInfo() throws KeywordSearchModuleException {
+ Index getIndexInfo() throws NoOpenCoreException {
currentCoreLock.readLock().lock();
try {
- if (null != currentCore) {
- return currentCore.getIndexInfo();
- } else {
- throw new KeywordSearchModuleException("Cannot get text index info, no core is open");
+ if (null == currentCore) {
+ throw new NoOpenCoreException();
}
+ return currentCore.getIndexInfo();
} finally {
currentCoreLock.readLock().unlock();
- }
+ }
}
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();
try {
+ if (null == currentCore) {
+ throw new NoOpenCoreException();
+ }
currentCore.addDocument(doc);
} finally {
currentCoreLock.readLock().unlock();
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
index 8e7f89c6c5..63ee08c10c 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java
@@ -179,7 +179,7 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService {
"SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
"SolrSearch.indentifyingIndex.msg=Identifying text index for upgrade",
"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"})
public void openCaseResources(CaseContext context) throws AutopsyServiceException {
ProgressIndicator progress = context.getProgressIndicator();
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java
index 7ecfdbe35a..c1149eee87 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java
@@ -347,6 +347,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
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_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
+
try {
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java
index 112984b33b..d62dffd155 100755
--- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java
+++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java
@@ -25,6 +25,7 @@ import junit.framework.Test;
import junit.framework.TestCase;
import org.netbeans.jemmy.Timeouts;
import org.netbeans.junit.NbModuleSuite;
+import org.sleuthkit.autopsy.core.UserPreferences;
/**
* 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() {
logger.info("######## " + AutopsyTestCases.getEscapedPath(System.getProperty("img_path")) + " #######");
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
}
/**
diff --git a/docs/doxygen-user/images/change_logical_file_set_display_name.PNG b/docs/doxygen-user/images/change_logical_file_set_display_name.PNG
index 6219181804..08528e9fed 100755
Binary files a/docs/doxygen-user/images/change_logical_file_set_display_name.PNG and b/docs/doxygen-user/images/change_logical_file_set_display_name.PNG differ
diff --git a/docs/doxygen-user/images/data-source-progress-bar.PNG b/docs/doxygen-user/images/data-source-progress-bar.PNG
index 747031914e..9957cf7830 100755
Binary files a/docs/doxygen-user/images/data-source-progress-bar.PNG and b/docs/doxygen-user/images/data-source-progress-bar.PNG differ
diff --git a/docs/doxygen-user/images/e01-verifier.PNG b/docs/doxygen-user/images/e01-verifier.PNG
index 3f5d3c3faa..f7b2cdf9b1 100755
Binary files a/docs/doxygen-user/images/e01-verifier.PNG and b/docs/doxygen-user/images/e01-verifier.PNG differ
diff --git a/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG b/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG
index b0ab22c6d0..9fb7daa33c 100755
Binary files a/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG and b/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG differ
diff --git a/docs/doxygen-user/images/hash-lookup.PNG b/docs/doxygen-user/images/hash-lookup.PNG
index 960892b20b..33f9ae804a 100755
Binary files a/docs/doxygen-user/images/hash-lookup.PNG and b/docs/doxygen-user/images/hash-lookup.PNG differ
diff --git a/docs/doxygen-user/images/interesting_files_ingest_settings.PNG b/docs/doxygen-user/images/interesting_files_ingest_settings.PNG
index c5dc42e20e..854a495862 100755
Binary files a/docs/doxygen-user/images/interesting_files_ingest_settings.PNG and b/docs/doxygen-user/images/interesting_files_ingest_settings.PNG differ
diff --git a/docs/doxygen-user/images/keyword-search-ingest-settings.PNG b/docs/doxygen-user/images/keyword-search-ingest-settings.PNG
index b55eca62c5..d7c0b8e2fc 100755
Binary files a/docs/doxygen-user/images/keyword-search-ingest-settings.PNG and b/docs/doxygen-user/images/keyword-search-ingest-settings.PNG differ
diff --git a/docs/doxygen-user/images/local-disk-data-source.PNG b/docs/doxygen-user/images/local-disk-data-source.PNG
index 22fdc40ec5..d9893b7de7 100644
Binary files a/docs/doxygen-user/images/local-disk-data-source.PNG and b/docs/doxygen-user/images/local-disk-data-source.PNG differ
diff --git a/docs/doxygen-user/images/profile-data-source-panel.PNG b/docs/doxygen-user/images/profile-data-source-panel.PNG
index e22a412d1d..debdf66ad5 100644
Binary files a/docs/doxygen-user/images/profile-data-source-panel.PNG and b/docs/doxygen-user/images/profile-data-source-panel.PNG differ
diff --git a/docs/doxygen-user/images/select-data-source-type.PNG b/docs/doxygen-user/images/select-data-source-type.PNG
index 2205f07d7b..41be35ff74 100755
Binary files a/docs/doxygen-user/images/select-data-source-type.PNG and b/docs/doxygen-user/images/select-data-source-type.PNG differ
diff --git a/docs/doxygen-user/images/select-ingest-modules.PNG b/docs/doxygen-user/images/select-ingest-modules.PNG
index fe359cbc15..9941a0dfb3 100755
Binary files a/docs/doxygen-user/images/select-ingest-modules.PNG and b/docs/doxygen-user/images/select-ingest-modules.PNG differ
diff --git a/docs/doxygen-user/images/unallocated_space_options.PNG b/docs/doxygen-user/images/unallocated_space_options.PNG
index 2f85e41b3d..a72fcc6dd8 100644
Binary files a/docs/doxygen-user/images/unallocated_space_options.PNG and b/docs/doxygen-user/images/unallocated_space_options.PNG differ
diff --git a/thunderbirdparser/release/modules/ext/java-libpst-1.0-SNAPSHOT.jar b/thirdparty/java-libpst/java-libpst-1.0-SNAPSHOT.jar
old mode 100755
new mode 100644
similarity index 100%
rename from thunderbirdparser/release/modules/ext/java-libpst-1.0-SNAPSHOT.jar
rename to thirdparty/java-libpst/java-libpst-1.0-SNAPSHOT.jar
diff --git a/thunderbirdparser/build.xml b/thunderbirdparser/build.xml
index c6442bd82f..098ed50445 100644
--- a/thunderbirdparser/build.xml
+++ b/thunderbirdparser/build.xml
@@ -2,7 +2,61 @@
-
+
Builds, tests, and runs the project org.sleuthkit.autopsy.thunderbirdparser.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thunderbirdparser/ivy.xml b/thunderbirdparser/ivy.xml
new file mode 100644
index 0000000000..4bf1f47c46
--- /dev/null
+++ b/thunderbirdparser/ivy.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thunderbirdparser/ivysettings.xml b/thunderbirdparser/ivysettings.xml
new file mode 100644
index 0000000000..c27d905255
--- /dev/null
+++ b/thunderbirdparser/ivysettings.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/thunderbirdparser/nbproject/project.properties b/thunderbirdparser/nbproject/project.properties
index fbdabd0fc1..e21eb352f8 100644
--- a/thunderbirdparser/nbproject/project.properties
+++ b/thunderbirdparser/nbproject/project.properties
@@ -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-SNAPSHOT.jar=release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.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-SNAPSHOT.jar=release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar
+file.reference.apache-mime4j-core-0.8.0.jar=release/modules/ext/apache-mime4j-core-0.8.0.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.jar=release/modules/ext/apache-mime4j-mbox-iterator-0.8.0.jar
file.reference.java-libpst-1.0-SNAPSHOT.jar=release/modules/ext/java-libpst-1.0-SNAPSHOT.jar
javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
diff --git a/thunderbirdparser/nbproject/project.xml b/thunderbirdparser/nbproject/project.xml
index 84f4663022..060c91a323 100644
--- a/thunderbirdparser/nbproject/project.xml
+++ b/thunderbirdparser/nbproject/project.xml
@@ -51,32 +51,20 @@
- ext/apache-mime4j-dom-0.8.0-SNAPSHOT-sources.jar
- release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT-sources.jar
+ ext/apache-mime4j-core-0.8.0.jar
+ release/modules/ext/apache-mime4j-core-0.8.0.jar
- ext/apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar
- release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar
-
-
- ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar
- release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar
-
-
- ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar
- release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar
-
-
- ext/apache-mime4j-dom-0.8.0-SNAPSHOT.jar
- release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT.jar
+ ext/apache-mime4j-dom-0.8.0.jar
+ release/modules/ext/apache-mime4j-dom-0.8.0.jar
ext/java-libpst-1.0-SNAPSHOT.jar
release/modules/ext/java-libpst-1.0-SNAPSHOT.jar
- ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar
- release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar
+ ext/apache-mime4j-mbox-iterator-0.8.0.jar
+ release/modules/ext/apache-mime4j-mbox-iterator-0.8.0.jar
diff --git a/thunderbirdparser/release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar b/thunderbirdparser/release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar
deleted file mode 100755
index 9e6f5b463e..0000000000
Binary files a/thunderbirdparser/release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT-sources.jar and /dev/null differ
diff --git a/thunderbirdparser/release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar b/thunderbirdparser/release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar
deleted file mode 100755
index 0aff45bb7d..0000000000
Binary files a/thunderbirdparser/release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar and /dev/null differ
diff --git a/thunderbirdparser/release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT-sources.jar b/thunderbirdparser/release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT-sources.jar
deleted file mode 100755
index 206408ba73..0000000000
Binary files a/thunderbirdparser/release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT-sources.jar and /dev/null differ
diff --git a/thunderbirdparser/release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT.jar b/thunderbirdparser/release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT.jar
deleted file mode 100755
index 773ab544ca..0000000000
Binary files a/thunderbirdparser/release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT.jar and /dev/null differ
diff --git a/thunderbirdparser/release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar b/thunderbirdparser/release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar
deleted file mode 100755
index f7248bd03e..0000000000
Binary files a/thunderbirdparser/release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT-sources.jar and /dev/null differ
diff --git a/thunderbirdparser/release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar b/thunderbirdparser/release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar
deleted file mode 100755
index bb7d15da61..0000000000
Binary files a/thunderbirdparser/release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar and /dev/null differ
diff --git a/thunderbirdparser/release/modules/ext/apache-mime4j-project-0.8.0-SNAPSHOT.jar b/thunderbirdparser/release/modules/ext/apache-mime4j-project-0.8.0-SNAPSHOT.jar
deleted file mode 100755
index 70beac46b5..0000000000
Binary files a/thunderbirdparser/release/modules/ext/apache-mime4j-project-0.8.0-SNAPSHOT.jar and /dev/null differ