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;
 
   82     @Messages ({
"ThunderbirdMboxFileIngestModule.noOpenCase.errMsg=Exception while getting open case."})
 
   89             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex);
 
  100             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex);
 
  105         if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
 
  110         if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) ||
 
  111                 (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
 
  115         if ((abstractFile.isFile() == 
false)) {
 
  120         boolean isMbox = 
false;
 
  122             byte[] t = 
new byte[64];
 
  123             if (abstractFile.getSize() > 64) {
 
  124                 int byteRead = abstractFile.read(t, 0, 64);
 
  126                     isMbox = MboxParser.isValidMimeTypeMbox(t);
 
  129         } 
catch (TskException ex) {
 
  130             logger.log(Level.WARNING, null, ex);
 
  137         if (PstParser.isPstFile(abstractFile)) {
 
  141         if (VcardParser.isVcardFile(abstractFile)) {
 
  155     @Messages({
"ThunderbirdMboxFileIngestModule.processPst.indexError.message=Failed to index encryption detected artifact for keyword search."})
 
  159             fileName = getTempPath() + File.separator + abstractFile.getName()
 
  160                 + 
"-" + String.valueOf(abstractFile.getId());
 
  162             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  165         File file = 
new File(fileName);
 
  169             logger.log(Level.WARNING, 
"Not enough disk space to write file to disk."); 
 
  171                     NbBundle.getMessage(this.getClass(),
 
  172                             "ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace",
 
  173                             abstractFile.getName()));
 
  180         } 
catch (IOException ex) {
 
  181             logger.log(Level.WARNING, 
"Failed writing pst file to disk.", ex); 
 
  185         PstParser parser = 
new PstParser(services);
 
  186         PstParser.ParseResult result = parser.parse(file, abstractFile.getId());
 
  188         if (result == PstParser.ParseResult.OK) {
 
  192         } 
else if (result == PstParser.ParseResult.ENCRYPT) {
 
  195                 BlackboardArtifact artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
 
  196                 artifact.addAttribute(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, 
EmailParserModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), 
"ThunderbirdMboxFileIngestModule.encryptionFileLevel")));
 
  203                     logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex); 
 
  207             } 
catch (TskCoreException ex) {
 
  208                 logger.log(Level.INFO, 
"Failed to add encryption attribute to file: {0}", abstractFile.getName()); 
 
  213                     NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
 
  214                             abstractFile.getName()),
 
  215                     NbBundle.getMessage(
this.getClass(),
 
  216                             "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
 
  217             logger.log(Level.INFO, 
"PSTParser failed to parse {0}", abstractFile.getName()); 
 
  221         if (file.delete() == 
false) {
 
  222             logger.log(Level.INFO, 
"Failed to delete temp file: {0}", file.getName()); 
 
  225         String errors = parser.getErrors();
 
  226         if (errors.isEmpty() == 
false) {
 
  228                     NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg2",
 
  229                             abstractFile.getName()), errors);
 
  243         String mboxFileName = abstractFile.getName();
 
  244         String mboxParentDir = abstractFile.getParentPath();
 
  246         String emailFolder = 
"";
 
  248         if (mboxParentDir.contains(
"/Mail/")) { 
 
  249             emailFolder = mboxParentDir.substring(mboxParentDir.indexOf(
"/Mail/") + 5); 
 
  250         } 
else if (mboxParentDir.contains(
"/ImapMail/")) { 
 
  251             emailFolder = mboxParentDir.substring(mboxParentDir.indexOf(
"/ImapMail/") + 9); 
 
  253         emailFolder = emailFolder + mboxFileName;
 
  254         emailFolder = emailFolder.replaceAll(
".sbd", 
""); 
 
  258             fileName = getTempPath() + File.separator + abstractFile.getName()
 
  259                 + 
"-" + String.valueOf(abstractFile.getId());
 
  261             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  264         File file = 
new File(fileName);
 
  268             logger.log(Level.WARNING, 
"Not enough disk space to write file to disk."); 
 
  270                     NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg",
 
  271                             abstractFile.getName()),
 
  272                     NbBundle.getMessage(
this.getClass(),
 
  273                             "ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details"));
 
  279         } 
catch (IOException ex) {
 
  280             logger.log(Level.WARNING, 
"Failed writing mbox file to disk.", ex); 
 
  284         MboxParser parser = 
new MboxParser(services, emailFolder);
 
  285         List<EmailMessage> emails = parser.parse(file, abstractFile.getId());
 
  288         if (file.delete() == 
false) {
 
  289             logger.log(Level.INFO, 
"Failed to delete temp file: {0}", file.getName()); 
 
  292         String errors = parser.getErrors();
 
  293         if (errors.isEmpty() == 
false) {
 
  295                     NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2",
 
  296                             abstractFile.getName()), errors);
 
  313         "ThunderbirdMboxFileIngestModule.errorMessage.outOfDiskSpace=Out of disk space. Cannot copy '{0}' (id={1}) to parse." 
  318             fileName = getTempPath() + File.separator + abstractFile.getName()
 
  319                 + 
"-" + String.valueOf(abstractFile.getId());
 
  321             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  324         File file = 
new File(fileName);
 
  328             logger.log(Level.WARNING, String.format(
"Not enough disk space to write file '%s' (id=%d) to disk.",
 
  329                     abstractFile.getName(), abstractFile.getId())); 
 
  331                     Bundle.ThunderbirdMboxFileIngestModule_errorMessage_outOfDiskSpace(abstractFile.getName(), abstractFile.getId()));
 
  338         } 
catch (IOException ex) {
 
  339             logger.log(Level.WARNING, String.format(
"Failed writing the vCard file '%s' (id=%d) to disk.",
 
  340                     abstractFile.getName(), abstractFile.getId()), ex); 
 
  345             VcardParser parser = 
new VcardParser(currentCase, context);
 
  346             parser.parse(file, abstractFile);
 
  348             logger.log(Level.WARNING, String.format(
"Exception while parsing the file '%s' (id=%d).", file.getName(), abstractFile.getId()), ex); 
 
  352         if (file.delete() == 
false) {
 
  353             logger.log(Level.INFO, 
"Failed to delete temp file: {0}", file.getName()); 
 
  368         File dir = 
new File(tmpDir);
 
  369         if (dir.exists() == 
false) {
 
  382     static String getModuleOutputPath() throws NoCurrentCaseException {
 
  383         String outDir = Case.getCurrentCaseThrows().getModuleDirectory() + File.separator
 
  384                 + EmailParserModuleFactory.getModuleName();
 
  385         File dir = 
new File(outDir);
 
  386         if (dir.exists() == 
false) {
 
  398     static String getRelModuleOutputPath() throws NoCurrentCaseException {
 
  399         return Case.getCurrentCaseThrows().getModuleOutputDirectoryRelativePath() + File.separator
 
  400                 + EmailParserModuleFactory.getModuleName();
 
  410     private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) {
 
  411         List<AbstractFile> derivedFiles = 
new ArrayList<>();
 
  415         for (EmailMessage email : emails) {
 
  418             if ((msgArtifact != null) && (email.hasAttachment()))  {
 
  419                 derivedFiles.addAll(
handleAttachments(email.getAttachments(), abstractFile, msgArtifact ));
 
  423         if (derivedFiles.isEmpty() == 
false) {
 
  424             for (AbstractFile derived : derivedFiles) {
 
  442     private List<AbstractFile> 
handleAttachments(List<EmailMessage.Attachment> attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact) {
 
  443         List<AbstractFile> files = 
new ArrayList<>();
 
  444         for (EmailMessage.Attachment attach : attachments) {
 
  445             String filename = attach.getName();
 
  446             long crTime = attach.getCrTime();
 
  447             long mTime = attach.getmTime();
 
  448             long aTime = attach.getaTime();
 
  449             long cTime = attach.getcTime();
 
  450             String relPath = attach.getLocalPath();
 
  451             long size = attach.getSize();
 
  452             TskData.EncodingType encodingType = attach.getEncodingType();
 
  456                         size, cTime, crTime, aTime, mTime, 
true, messageArtifact, 
"",
 
  459             } 
catch (TskCoreException ex) {
 
  461                         NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.handleAttch.errMsg",
 
  462                                 abstractFile.getName()),
 
  463                         NbBundle.getMessage(
this.getClass(),
 
  464                                 "ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename));
 
  465                 logger.log(Level.INFO, 
"", ex);
 
  479         Pattern p = Pattern.compile(
"\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
 
  480                                     Pattern.CASE_INSENSITIVE);
 
  481         Matcher m = p.matcher(input);
 
  482         Set<String> emailAddresses = 
new HashSet<>();
 
  484             emailAddresses.add( m.group());
 
  486         return emailAddresses;
 
  497     @Messages({
"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."})
 
  498     private BlackboardArtifact 
addEmailArtifact(EmailMessage email, AbstractFile abstractFile) {
 
  499         BlackboardArtifact bbart = null;
 
  500         List<BlackboardAttribute> bbattributes = 
new ArrayList<>();
 
  501         String to = email.getRecipients();
 
  502         String cc = email.getCc();
 
  503         String bcc = email.getBcc();
 
  504         String from = email.getSender();
 
  505         long dateL = email.getSentDate();
 
  506         String headers = email.getHeaders();
 
  507         String body = email.getTextBody();
 
  508         String bodyHTML = email.getHtmlBody();
 
  509         String rtf = email.getRtfBody();
 
  510         String subject = email.getSubject();
 
  511         long id = email.getId();
 
  512         String localPath = email.getLocalPath();
 
  514         List<String> senderAddressList = 
new ArrayList<>();
 
  515         String senderAddress;
 
  518         AccountFileInstance senderAccountInstance = null;
 
  520         if (senderAddressList.size() == 1) {
 
  521             senderAddress = senderAddressList.get(0);
 
  523                 senderAccountInstance = currentCase.
getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, 
EmailParserModuleFactory.getModuleName(), abstractFile);
 
  525             catch(TskCoreException ex) {
 
  526                  logger.log(Level.WARNING, 
"Failed to create account for email address  " + senderAddress, ex); 
 
  530              logger.log(Level.WARNING, 
"Failed to find sender address, from  = {0}", from); 
 
  533         List<String> recipientAddresses = 
new ArrayList<>();
 
  538         List<AccountFileInstance> recipientAccountInstances = 
new ArrayList<>();
 
  539         recipientAddresses.forEach((addr) -> {
 
  541                 AccountFileInstance recipientAccountInstance = 
 
  542                 currentCase.
getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
 
  544                 recipientAccountInstances.add(recipientAccountInstance);
 
  546             catch(TskCoreException ex) {
 
  547                 logger.log(Level.WARNING, 
"Failed to create account for email address  " + addr, ex); 
 
  551         addArtifactAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
 
  552         addArtifactAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
 
  553         addArtifactAttribute(to, ATTRIBUTE_TYPE.TSK_EMAIL_TO, bbattributes);
 
  554         addArtifactAttribute(subject, ATTRIBUTE_TYPE.TSK_SUBJECT, bbattributes);
 
  556         addArtifactAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, bbattributes);
 
  557         addArtifactAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_SENT, bbattributes);
 
  559         addArtifactAttribute(body, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, bbattributes);
 
  561         addArtifactAttribute(((
id < 0L) ? NbBundle.getMessage(
this.getClass(), 
"ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(
id)), 
 
  562                 ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
 
  564         addArtifactAttribute(((localPath.isEmpty() == 
false) ? localPath : 
"/foo/bar"), 
 
  565                 ATTRIBUTE_TYPE.TSK_PATH, bbattributes);
 
  567         addArtifactAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes);
 
  568         addArtifactAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
 
  569         addArtifactAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes);
 
  574             bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
 
  575             bbart.addAttributes(bbattributes);
 
  578             currentCase.
getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
 
  584                 logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + bbart.getArtifactID(), ex); 
 
  587         } 
catch (TskCoreException | TskDataException ex) {
 
  588             logger.log(Level.WARNING, null, ex);
 
  601     static void addArtifactAttribute(String stringVal, BlackboardAttribute.Type attrType, Collection<BlackboardAttribute> bbattributes) {
 
  602         if (stringVal.isEmpty() == 
false) {
 
  614     static void addArtifactAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
 
  615         if (stringVal.isEmpty() == 
false) {
 
  616             bbattributes.add(
new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), stringVal));
 
  627     static void addArtifactAttribute(
long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
 
  629             bbattributes.add(
new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), longVal));
 
  639     void postErrorMessage(String subj, String details) {
 
  640         IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
 
  649     IngestServices getServices() {
 
Set< String > findEmailAddresess(String input)
static final Logger logger
FileManager getFileManager()
String getTempDirectory()
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
BlackboardArtifact addEmailArtifact(EmailMessage email, AbstractFile abstractFile)
final IngestServices services
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)
ProcessResult processMBox(AbstractFile abstractFile)
static final int DISK_FREE_SPACE_UNKNOWN
void processEmails(List< EmailMessage > emails, AbstractFile abstractFile)
ProcessResult processVcard(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()