19 package org.sleuthkit.autopsy.thunderbirdparser;
 
   22 import java.io.IOException;
 
   23 import java.util.ArrayList;
 
   24 import java.util.Collection;
 
   25 import java.util.HashSet;
 
   26 import java.util.List;
 
   28 import java.util.logging.Level;
 
   29 import java.util.regex.Matcher;
 
   30 import java.util.regex.Pattern;
 
   31 import org.openide.util.NbBundle;
 
   32 import org.openide.util.NbBundle.Messages;
 
   53 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
 
   78     @Messages ({
"ThunderbirdMboxFileIngestModule.noOpenCase.errMsg=Exception while getting open case."})
 
   84             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex);
 
   95             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex);
 
  100         if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
 
  105         if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) ||
 
  106                 (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
 
  110         if ((abstractFile.isFile() == 
false)) {
 
  115         boolean isMbox = 
false;
 
  117             byte[] t = 
new byte[64];
 
  118             if (abstractFile.getSize() > 64) {
 
  119                 int byteRead = abstractFile.read(t, 0, 64);
 
  121                     isMbox = MboxParser.isValidMimeTypeMbox(t);
 
  124         } 
catch (TskException ex) {
 
  125             logger.log(Level.WARNING, null, ex);
 
  132         if (PstParser.isPstFile(abstractFile)) {
 
  146     @Messages({
"ThunderbirdMboxFileIngestModule.processPst.indexError.message=Failed to index encryption detected artifact for keyword search."})
 
  150             fileName = getTempPath() + File.separator + abstractFile.getName()
 
  151                 + 
"-" + String.valueOf(abstractFile.getId());
 
  153             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  156         File file = 
new File(fileName);
 
  160             logger.log(Level.WARNING, 
"Not enough disk space to write file to disk."); 
 
  162                     NbBundle.getMessage(this.getClass(),
 
  163                             "ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace",
 
  164                             abstractFile.getName()));
 
  171         } 
catch (IOException ex) {
 
  172             logger.log(Level.WARNING, 
"Failed writing pst file to disk.", ex); 
 
  176         PstParser parser = 
new PstParser(services);
 
  177         PstParser.ParseResult result = parser.parse(file, abstractFile.getId());
 
  179         if (result == PstParser.ParseResult.OK) {
 
  184                 logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  188         } 
else if (result == PstParser.ParseResult.ENCRYPT) {
 
  191                 BlackboardArtifact artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
 
  192                 artifact.addAttribute(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, 
EmailParserModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), 
"ThunderbirdMboxFileIngestModule.encryptionFileLevel")));
 
  199                     logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex); 
 
  203             } 
catch (TskCoreException ex) {
 
  204                 logger.log(Level.INFO, 
"Failed to add encryption attribute to file: {0}", abstractFile.getName()); 
 
  209                     NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
 
  210                             abstractFile.getName()),
 
  211                     NbBundle.getMessage(
this.getClass(),
 
  212                             "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
 
  213             logger.log(Level.INFO, 
"PSTParser failed to parse {0}", abstractFile.getName()); 
 
  217         if (file.delete() == 
false) {
 
  218             logger.log(Level.INFO, 
"Failed to delete temp file: {0}", file.getName()); 
 
  221         String errors = parser.getErrors();
 
  222         if (errors.isEmpty() == 
false) {
 
  224                     NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg2",
 
  225                             abstractFile.getName()), errors);
 
  239         String mboxFileName = abstractFile.getName();
 
  240         String mboxParentDir = abstractFile.getParentPath();
 
  242         String emailFolder = 
"";
 
  244         if (mboxParentDir.contains(
"/Mail/")) { 
 
  245             emailFolder = mboxParentDir.substring(mboxParentDir.indexOf(
"/Mail/") + 5); 
 
  246         } 
else if (mboxParentDir.contains(
"/ImapMail/")) { 
 
  247             emailFolder = mboxParentDir.substring(mboxParentDir.indexOf(
"/ImapMail/") + 9); 
 
  249         emailFolder = emailFolder + mboxFileName;
 
  250         emailFolder = emailFolder.replaceAll(
".sbd", 
""); 
 
  254             fileName = getTempPath() + File.separator + abstractFile.getName()
 
  255                 + 
"-" + String.valueOf(abstractFile.getId());
 
  257             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  260         File file = 
new File(fileName);
 
  264             logger.log(Level.WARNING, 
"Not enough disk space to write file to disk."); 
 
  266                     NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg",
 
  267                             abstractFile.getName()),
 
  268                     NbBundle.getMessage(
this.getClass(),
 
  269                             "ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details"));
 
  275         } 
catch (IOException ex) {
 
  276             logger.log(Level.WARNING, 
"Failed writing mbox file to disk.", ex); 
 
  280         MboxParser parser = 
new MboxParser(services, emailFolder);
 
  281         List<EmailMessage> emails = parser.parse(file, abstractFile.getId());
 
  285             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  289         if (file.delete() == 
false) {
 
  290             logger.log(Level.INFO, 
"Failed to delete temp file: {0}", file.getName()); 
 
  293         String errors = parser.getErrors();
 
  294         if (errors.isEmpty() == 
false) {
 
  296                     NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2",
 
  297                             abstractFile.getName()), errors);
 
  312         File dir = 
new File(tmpDir);
 
  313         if (dir.exists() == 
false) {
 
  325     static String getModuleOutputPath() throws NoCurrentCaseException {
 
  326         String outDir = Case.getCurrentCaseThrows().getModuleDirectory() + File.separator
 
  327                 + EmailParserModuleFactory.getModuleName();
 
  328         File dir = 
new File(outDir);
 
  329         if (dir.exists() == 
false) {
 
  341     static String getRelModuleOutputPath() throws NoCurrentCaseException {
 
  342         return Case.getCurrentCaseThrows().getModuleOutputDirectoryRelativePath() + File.separator
 
  343                 + EmailParserModuleFactory.getModuleName();
 
  354     private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) 
throws NoCurrentCaseException {
 
  355         List<AbstractFile> derivedFiles = 
new ArrayList<>();
 
  359         for (EmailMessage email : emails) {
 
  360             BlackboardArtifact msgArtifact = 
addArtifact(email, abstractFile);
 
  362             if ((msgArtifact != null) && (email.hasAttachment()))  {
 
  363                 derivedFiles.addAll(
handleAttachments(email.getAttachments(), abstractFile, msgArtifact ));
 
  367         if (derivedFiles.isEmpty() == 
false) {
 
  368             for (AbstractFile derived : derivedFiles) {
 
  386     private List<AbstractFile> 
handleAttachments(List<EmailMessage.Attachment> attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact) {
 
  387         List<AbstractFile> files = 
new ArrayList<>();
 
  388         for (EmailMessage.Attachment attach : attachments) {
 
  389             String filename = attach.getName();
 
  390             long crTime = attach.getCrTime();
 
  391             long mTime = attach.getmTime();
 
  392             long aTime = attach.getaTime();
 
  393             long cTime = attach.getcTime();
 
  394             String relPath = attach.getLocalPath();
 
  395             long size = attach.getSize();
 
  396             TskData.EncodingType encodingType = attach.getEncodingType();
 
  400                         size, cTime, crTime, aTime, mTime, 
true, messageArtifact, 
"",
 
  403             } 
catch (TskCoreException ex) {
 
  405                         NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.handleAttch.errMsg",
 
  406                                 abstractFile.getName()),
 
  407                         NbBundle.getMessage(
this.getClass(),
 
  408                                 "ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename));
 
  409                 logger.log(Level.INFO, 
"", ex);
 
  423         Pattern p = Pattern.compile(
"\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
 
  424                                     Pattern.CASE_INSENSITIVE);
 
  425         Matcher m = p.matcher(input);
 
  426         Set<String> emailAddresses = 
new HashSet<String>();
 
  428             emailAddresses.add( m.group());
 
  430         return emailAddresses;
 
  440     @Messages({
"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."})
 
  441     private BlackboardArtifact 
addArtifact(EmailMessage email, AbstractFile abstractFile) 
throws NoCurrentCaseException {
 
  442         BlackboardArtifact bbart = null;
 
  443         List<BlackboardAttribute> bbattributes = 
new ArrayList<>();
 
  444         String to = email.getRecipients();
 
  445         String cc = email.getCc();
 
  446         String bcc = email.getBcc();
 
  447         String from = email.getSender();
 
  448         long dateL = email.getSentDate();
 
  449         String headers = email.getHeaders();
 
  450         String body = email.getTextBody();
 
  451         String bodyHTML = email.getHtmlBody();
 
  452         String rtf = email.getRtfBody();
 
  453         String subject = email.getSubject();
 
  454         long id = email.getId();
 
  455         String localPath = email.getLocalPath();
 
  457         List<String> senderAddressList = 
new ArrayList<>();
 
  458         String senderAddress;
 
  461         AccountFileInstance senderAccountInstance = null;
 
  465         if (senderAddressList.size() == 1) {
 
  466             senderAddress = senderAddressList.get(0);
 
  468                 senderAccountInstance = openCase.
getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, 
EmailParserModuleFactory.getModuleName(), abstractFile);
 
  470             catch(TskCoreException ex) {
 
  471                  logger.log(Level.WARNING, 
"Failed to create account for email address  " + senderAddress, ex); 
 
  475              logger.log(Level.WARNING, 
"Failed to find sender address, from  = "+ from); 
 
  478         List<String> recipientAddresses = 
new ArrayList<>();
 
  483         List<AccountFileInstance> recipientAccountInstances = 
new ArrayList<>();
 
  484         recipientAddresses.forEach((addr) -> {
 
  486                 AccountFileInstance recipientAccountInstance = 
 
  487                 openCase.
getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
 
  489                 recipientAccountInstances.add(recipientAccountInstance);
 
  491             catch(TskCoreException ex) {
 
  492                 logger.log(Level.WARNING, 
"Failed to create account for email address  " + addr, ex); 
 
  506         addEmailAttribute(((
id < 0L) ? NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(
id)), 
 
  507                 ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
 
  510                 ATTRIBUTE_TYPE.TSK_PATH, bbattributes);
 
  513         addEmailAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
 
  519             bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
 
  520             bbart.addAttributes(bbattributes);
 
  523             openCase.
getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
 
  529                 logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + bbart.getArtifactID(), ex); 
 
  532         } 
catch (TskCoreException | TskDataException ex) {
 
  533             logger.log(Level.WARNING, null, ex);
 
  539     private void addEmailAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
 
  540         if (stringVal.isEmpty() == 
false) {
 
  544     private void addEmailAttribute(
long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
 
  550     void postErrorMessage(String subj, String details) {
 
  555     IngestServices getServices() {
 
Set< String > findEmailAddresess(String input)
 
static final Logger logger
 
FileManager getFileManager()
 
String getTempDirectory()
 
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
 
void addEmailAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection< BlackboardAttribute > bbattributes)
 
BlackboardArtifact addArtifact(EmailMessage email, AbstractFile abstractFile)
 
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
 
synchronized DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
 
void addEmailAttribute(long longVal, ATTRIBUTE_TYPE attrType, Collection< BlackboardAttribute > bbattributes)
 
ProcessResult processMBox(AbstractFile abstractFile)
 
static final int DISK_FREE_SPACE_UNKNOWN
 
void processEmails(List< EmailMessage > emails, AbstractFile abstractFile)
 
void addFilesToJob(List< AbstractFile > files)
 
void postMessage(final IngestMessage message)
 
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
 
ProcessResult process(AbstractFile abstractFile)
 
SleuthkitCase getSleuthkitCase()
 
ProcessResult processPst(AbstractFile abstractFile)
 
void startUp(IngestJobContext context)
 
Blackboard getBlackboard()
 
void fireModuleContentEvent(ModuleContentEvent moduleContentEvent)
 
static void error(String title, String message)
 
synchronized void indexArtifact(BlackboardArtifact artifact)
 
synchronized static Logger getLogger(String name)
 
static Case getCurrentCaseThrows()
 
List< AbstractFile > handleAttachments(List< EmailMessage.Attachment > attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact)
 
static synchronized IngestServices getInstance()