Autopsy  4.15.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ThunderbirdMboxFileIngestModule.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.thunderbirdparser;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.logging.Level;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33 import org.apache.james.mime4j.MimeException;
34 import org.openide.util.NbBundle;
35 import org.openide.util.NbBundle.Messages;
49 import org.sleuthkit.datamodel.AbstractFile;
50 import org.sleuthkit.datamodel.Account;
51 import org.sleuthkit.datamodel.AccountFileInstance;
52 import org.sleuthkit.datamodel.Blackboard;
53 import org.sleuthkit.datamodel.BlackboardArtifact;
54 import org.sleuthkit.datamodel.BlackboardAttribute;
55 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
56 import org.sleuthkit.datamodel.DerivedFile;
57 import org.sleuthkit.datamodel.ReadContentInputStream;
58 import org.sleuthkit.datamodel.Relationship;
59 import org.sleuthkit.datamodel.TskCoreException;
60 import org.sleuthkit.datamodel.TskData;
61 import org.sleuthkit.datamodel.TskDataException;
62 import org.sleuthkit.datamodel.TskException;
63 import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper;
64 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments;
65 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.FileAttachment;
66 
72 public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
73  private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName());
77  private Blackboard blackboard;
78  private CommunicationArtifactsHelper communicationArtifactsHelper;
79 
80  private static final int MBOX_SIZE_TO_SPLIT = 1048576000;
81  private Case currentCase;
82 
87  }
88 
89  @Override
90  @Messages ({"ThunderbirdMboxFileIngestModule.noOpenCase.errMsg=Exception while getting open case."})
91  public void startUp(IngestJobContext context) throws IngestModuleException {
92  this.context = context;
93  try {
94  currentCase = Case.getCurrentCaseThrows();
96  } catch (NoCurrentCaseException ex) {
97  logger.log(Level.SEVERE, "Exception while getting open case.", ex);
98  throw new IngestModuleException(Bundle.ThunderbirdMboxFileIngestModule_noOpenCase_errMsg(), ex);
99  }
100  }
101 
102  @Override
103  public ProcessResult process(AbstractFile abstractFile) {
104 
105  blackboard = currentCase.getSleuthkitCase().getBlackboard();
106 
107  // skip known
108  if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
109  return ProcessResult.OK;
110  }
111 
112  //skip unalloc
113  if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) ||
114  (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
115  return ProcessResult.OK;
116  }
117 
118  if ((abstractFile.isFile() == false)) {
119  return ProcessResult.OK;
120  }
121 
122  // check its signature
123  boolean isMbox = false;
124  boolean isEMLFile = false;
125 
126  try {
127  byte[] t = new byte[64];
128  if (abstractFile.getSize() > 64) {
129  int byteRead = abstractFile.read(t, 0, 64);
130  if (byteRead > 0) {
131  isMbox = MboxParser.isValidMimeTypeMbox(t);
132  isEMLFile = EMLParser.isEMLFile(abstractFile, t);
133  }
134  }
135  } catch (TskException ex) {
136  logger.log(Level.WARNING, null, ex);
137  }
138 
139  boolean isPstFile = PstParser.isPstFile(abstractFile);
140  boolean isVcardFile = VcardParser.isVcardFile(abstractFile);
141 
142  if (isMbox || isEMLFile || isPstFile || isVcardFile ) {
143  try {
144  communicationArtifactsHelper = new CommunicationArtifactsHelper(currentCase.getSleuthkitCase(),
145  EmailParserModuleFactory.getModuleName(), abstractFile, Account.Type.EMAIL);
146  } catch (TskCoreException ex) {
147  logger.log(Level.SEVERE, String.format("Failed to create CommunicationArtifactsHelper for file with object id = %d", abstractFile.getId()), ex);
148  return ProcessResult.ERROR;
149  }
150  }
151 
152  if (isMbox) {
153  return processMBox(abstractFile);
154  }
155 
156  if (isEMLFile) {
157  return processEMLFile(abstractFile);
158  }
159 
160  if (isPstFile) {
161  return processPst(abstractFile);
162  }
163 
164  if (isVcardFile) {
165  return processVcard(abstractFile);
166  }
167 
168  return ProcessResult.OK;
169  }
170 
178  @Messages({"ThunderbirdMboxFileIngestModule.processPst.indexError.message=Failed to index encryption detected artifact for keyword search."})
179  private ProcessResult processPst(AbstractFile abstractFile) {
180  String fileName;
181  try {
182  fileName = getTempPath() + File.separator + abstractFile.getName()
183  + "-" + String.valueOf(abstractFile.getId());
184  } catch (NoCurrentCaseException ex) {
185  logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
186  return ProcessResult.ERROR;
187  }
188  File file = new File(fileName);
189 
190  long freeSpace = services.getFreeDiskSpace();
191  if ((freeSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN) && (abstractFile.getSize() >= freeSpace)) {
192  logger.log(Level.WARNING, "Not enough disk space to write file to disk."); //NON-NLS
194  NbBundle.getMessage(this.getClass(),
195  "ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace",
196  abstractFile.getName()));
197  services.postMessage(msg);
198  return ProcessResult.OK;
199  }
200 
201  try {
202  ContentUtils.writeToFile(abstractFile, file, context::fileIngestIsCancelled);
203  } catch (IOException ex) {
204  logger.log(Level.WARNING, "Failed writing pst file to disk.", ex); //NON-NLS
205  return ProcessResult.OK;
206  }
207 
208  PstParser parser = new PstParser(services);
209  PstParser.ParseResult result = parser.open(file, abstractFile.getId());
210 
211  switch( result) {
212  case OK:
213  Iterator<EmailMessage> pstMsgIterator = parser.getEmailMessageIterator();
214  if (pstMsgIterator != null) {
215  processEmails(parser.getPartialEmailMessages(), pstMsgIterator , abstractFile);
216  } else {
217  // sometimes parser returns ParseResult=OK but there are no messages
218  postErrorMessage(
219  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
220  abstractFile.getName()),
221  NbBundle.getMessage(this.getClass(),
222  "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
223  logger.log(Level.INFO, "PSTParser failed to parse {0}", abstractFile.getName()); //NON-NLS
224  // delete the temp file
225  if (file.delete() == false) {
226  logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
227  }
228  return ProcessResult.ERROR;
229  }
230  break;
231 
232  case ENCRYPT:
233  // encrypted pst: Add encrypted file artifact
234  try {
235 
236  BlackboardArtifact artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
237  artifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, EmailParserModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.encryptionFileLevel")));
238 
239  try {
240  // index the artifact for keyword search
241  blackboard.postArtifact(artifact, EmailParserModuleFactory.getModuleName());
242  } catch (Blackboard.BlackboardException ex) {
243  MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_processPst_indexError_message(), artifact.getDisplayName());
244  logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
245  }
246  } catch (TskCoreException ex) {
247  logger.log(Level.INFO, "Failed to add encryption attribute to file: {0}", abstractFile.getName()); //NON-NLS
248  }
249  break;
250  default:
251  // parsing error: log message
252  postErrorMessage(
253  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
254  abstractFile.getName()),
255  NbBundle.getMessage(this.getClass(),
256  "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
257  logger.log(Level.INFO, "PSTParser failed to parse {0}", abstractFile.getName()); //NON-NLS
258  // delete the temp file
259  if (file.delete() == false) {
260  logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
261  }
262  return ProcessResult.ERROR;
263  }
264 
265  if (file.delete() == false) {
266  logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
267  }
268 
269  return ProcessResult.OK;
270  }
271 
279  private ProcessResult processMBox(AbstractFile abstractFile) {
280  String mboxFileName = abstractFile.getName();
281  String mboxParentDir = abstractFile.getParentPath();
282  // use the local path to determine the e-mail folder structure
283  String emailFolder = "";
284  // email folder is everything after "Mail" or ImapMail
285  if (mboxParentDir.contains("/Mail/")) { //NON-NLS
286  emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/Mail/") + 5); //NON-NLS
287  } else if (mboxParentDir.contains("/ImapMail/")) { //NON-NLS
288  emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/ImapMail/") + 9); //NON-NLS
289  }
290  emailFolder += mboxFileName;
291  emailFolder = emailFolder.replaceAll(".sbd", ""); //NON-NLS
292 
293  String fileName;
294  try {
295  fileName = getTempPath() + File.separator + abstractFile.getName()
296  + "-" + String.valueOf(abstractFile.getId());
297  } catch (NoCurrentCaseException ex) {
298  logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
299  return ProcessResult.ERROR;
300  }
301  File file = new File(fileName);
302 
303  long freeSpace = services.getFreeDiskSpace();
304  if ((freeSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN) && (abstractFile.getSize() >= freeSpace)) {
305  logger.log(Level.WARNING, "Not enough disk space to write file to disk."); //NON-NLS
306  postErrorMessage(
307  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg",
308  abstractFile.getName()),
309  NbBundle.getMessage(this.getClass(),
310  "ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details"));
311  return ProcessResult.OK;
312  }
313 
314  if (abstractFile.getSize() < MBOX_SIZE_TO_SPLIT) {
315 
316  try {
317  ContentUtils.writeToFile(abstractFile, file, context::fileIngestIsCancelled);
318  } catch (IOException ex) {
319  logger.log(Level.WARNING, "Failed writing mbox file to disk.", ex); //NON-NLS
320  return ProcessResult.OK;
321  }
322 
323  processMboxFile(file, abstractFile, emailFolder);
324 
325  if (file.delete() == false) {
326  logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
327  }
328  } else {
329 
330  List<Long> mboxSplitOffsets = new ArrayList<>();
331  try{
332  mboxSplitOffsets = findMboxSplitOffset(abstractFile, file);
333  } catch (IOException ex) {
334  logger.log(Level.WARNING, String.format("Failed finding split offsets for mbox file {0}.", fileName), ex); //NON-NLS
335  return ProcessResult.OK;
336  }
337 
338  long startingOffset = 0;
339  for (Long mboxSplitOffset : mboxSplitOffsets) {
340  File splitFile = new File(fileName + "-" + mboxSplitOffset);
341  try {
342  ContentUtils.writeToFile(abstractFile, splitFile, context::fileIngestIsCancelled, startingOffset, mboxSplitOffset);
343  } catch (IOException ex) {
344  logger.log(Level.WARNING, "Failed writing split mbox file to disk.", ex); //NON-NLS
345  return ProcessResult.OK;
346  }
347  processMboxFile(splitFile, abstractFile, emailFolder);
348  startingOffset = mboxSplitOffset;
349  if (splitFile.delete() == false) {
350  logger.log(Level.INFO, "Failed to delete temp file: {0}", splitFile); //NON-NLS
351  }
352 
353  }
354  }
355 
356  return ProcessResult.OK;
357  }
358 
359  private List<Long> findMboxSplitOffset(AbstractFile abstractFile, File file) throws IOException {
360 
361  List<Long> mboxSplitOffset = new ArrayList<>();
362 
363  byte[] buffer = new byte[7];
364  ReadContentInputStream in = new ReadContentInputStream(abstractFile);
365  in.skip(MBOX_SIZE_TO_SPLIT);
366  int len = in.read(buffer);
367  while (len != -1) {
368  len = in.read(buffer);
369  if (buffer[0] == 13 && buffer[1] == 10 && buffer[2] == 70 && buffer[3] == 114 &&
370  buffer[4] == 111 && buffer[5] == 109 && buffer[6] == 32) {
371  mboxSplitOffset.add(in.getCurPosition() - 5 );
372  in.skip(MBOX_SIZE_TO_SPLIT);
373  }
374  }
375 
376  return mboxSplitOffset;
377 
378  }
379 
380 
381  private void processMboxFile(File file, AbstractFile abstractFile, String emailFolder) {
382 
383 
384  MboxParser emailIterator = MboxParser.getEmailIterator( emailFolder, file, abstractFile.getId());
385  List<EmailMessage> emails = new ArrayList<>();
386  if(emailIterator != null) {
387  while(emailIterator.hasNext()) {
388  EmailMessage emailMessage = emailIterator.next();
389  if(emailMessage != null) {
390  emails.add(emailMessage);
391  }
392  }
393 
394  String errors = emailIterator.getErrors();
395  if (!errors.isEmpty()) {
396  postErrorMessage(
397  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2",
398  abstractFile.getName()), errors);
399  }
400  }
401  processEmails(emails, MboxParser.getEmailIterator( emailFolder, file, abstractFile.getId()), abstractFile);
402 
403  }
404 
413  @Messages({
414  "# {0} - file name",
415  "# {1} - file ID",
416  "ThunderbirdMboxFileIngestModule.errorMessage.outOfDiskSpace=Out of disk space. Cannot copy '{0}' (id={1}) to parse."
417  })
418  private ProcessResult processVcard(AbstractFile abstractFile) {
419  try {
420  VcardParser parser = new VcardParser(currentCase, context);
421  parser.parse(abstractFile);
422  } catch (IOException | NoCurrentCaseException ex) {
423  logger.log(Level.WARNING, String.format("Exception while parsing the file '%s' (id=%d).", abstractFile.getName(), abstractFile.getId()), ex); //NON-NLS
424  return ProcessResult.OK;
425  }
426  return ProcessResult.OK;
427  }
428 
429  private ProcessResult processEMLFile(AbstractFile abstractFile) {
430  try {
431  EmailMessage message = EMLParser.parse(abstractFile);
432 
433  if (message == null) {
434  return ProcessResult.OK;
435  }
436 
437  List<AbstractFile> derivedFiles = new ArrayList<>();
438 
439  BlackboardArtifact msgArtifact = addEmailArtifact(message, abstractFile);
440 
441  if ((msgArtifact != null) && (message.hasAttachment())) {
442  derivedFiles.addAll(handleAttachments(message.getAttachments(), abstractFile, msgArtifact));
443  }
444 
445  if (derivedFiles.isEmpty() == false) {
446  for (AbstractFile derived : derivedFiles) {
447  services.fireModuleContentEvent(new ModuleContentEvent(derived));
448  }
449  }
450  context.addFilesToJob(derivedFiles);
451 
452  } catch (IOException ex) {
453  logger.log(Level.WARNING, String.format("Error reading eml file %s", abstractFile.getName()), ex);
454  return ProcessResult.ERROR;
455  } catch (MimeException ex) {
456  logger.log(Level.WARNING, String.format("Error reading eml file %s", abstractFile.getName()), ex);
457  return ProcessResult.ERROR;
458  }
459 
460  return ProcessResult.OK;
461  }
462 
469  static String getTempPath() throws NoCurrentCaseException {
470  String tmpDir = Case.getCurrentCaseThrows().getTempDirectory() + File.separator
471  + "EmailParser"; //NON-NLS
472  File dir = new File(tmpDir);
473  if (dir.exists() == false) {
474  dir.mkdirs();
475  }
476  return tmpDir;
477  }
478 
486  static String getModuleOutputPath() throws NoCurrentCaseException {
487  String outDir = Case.getCurrentCaseThrows().getModuleDirectory() + File.separator
488  + EmailParserModuleFactory.getModuleName();
489  File dir = new File(outDir);
490  if (dir.exists() == false) {
491  dir.mkdirs();
492  }
493  return outDir;
494  }
495 
502  static String getRelModuleOutputPath() throws NoCurrentCaseException {
503  return Case.getCurrentCaseThrows().getModuleOutputDirectoryRelativePath() + File.separator
504  + EmailParserModuleFactory.getModuleName();
505  }
506 
515  private void processEmails(List<EmailMessage> partialEmailsForThreading, Iterator<EmailMessage> fullMessageIterator, AbstractFile abstractFile) {
516 
517  // Putting try/catch around this to catch any exception and still allow
518  // the creation of the artifacts to continue.
519  try{
520  EmailMessageThreader.threadMessages(partialEmailsForThreading);
521  } catch(Exception ex) {
522  logger.log(Level.WARNING, String.format("Exception thrown parsing emails from %s", abstractFile.getName()), ex);
523  }
524 
525  List<AbstractFile> derivedFiles = new ArrayList<>();
526 
527  int msgCnt = 0;
528  while(fullMessageIterator.hasNext()) {
529  EmailMessage current = fullMessageIterator.next();
530 
531  if(current == null) {
532  continue;
533  }
534 
535  if(partialEmailsForThreading.size() > msgCnt) {
536  EmailMessage threaded = partialEmailsForThreading.get(msgCnt++);
537 
538  if(threaded.getMessageID().equals(current.getMessageID()) &&
539  threaded.getSubject().equals(current.getSubject())) {
540  current.setMessageThreadID(threaded.getMessageThreadID());
541  }
542  }
543 
544  BlackboardArtifact msgArtifact = addEmailArtifact(current, abstractFile);
545 
546  if ((msgArtifact != null) && (current.hasAttachment())) {
547  derivedFiles.addAll(handleAttachments(current.getAttachments(), abstractFile, msgArtifact ));
548  }
549  }
550 
551  if (derivedFiles.isEmpty() == false) {
552  for (AbstractFile derived : derivedFiles) {
553  services.fireModuleContentEvent(new ModuleContentEvent(derived));
554  }
555  }
556  context.addFilesToJob(derivedFiles);
557  }
568  @NbBundle.Messages({
569  "ThunderbirdMboxFileIngestModule.handleAttch.addAttachmentsErrorMsg=Failed to add attachments to email message."
570 })
571  private List<AbstractFile> handleAttachments(List<EmailMessage.Attachment> attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact) {
572  List<AbstractFile> files = new ArrayList<>();
573  List<FileAttachment> fileAttachments = new ArrayList<>();
574  for (EmailMessage.Attachment attach : attachments) {
575  String filename = attach.getName();
576  long crTime = attach.getCrTime();
577  long mTime = attach.getmTime();
578  long aTime = attach.getaTime();
579  long cTime = attach.getcTime();
580  String relPath = attach.getLocalPath();
581  long size = attach.getSize();
582  TskData.EncodingType encodingType = attach.getEncodingType();
583 
584  try {
585  DerivedFile df = fileManager.addDerivedFile(filename, relPath,
586  size, cTime, crTime, aTime, mTime, true, abstractFile, "",
587  EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleVersion(), "", encodingType);
588 
589  associateAttachmentWithMesssge(messageArtifact, df);
590 
591  files.add(df);
592 
593  fileAttachments.add(new FileAttachment(df));
594  } catch (TskCoreException ex) {
595  postErrorMessage(
596  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.handleAttch.errMsg",
597  abstractFile.getName()),
598  NbBundle.getMessage(this.getClass(),
599  "ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename));
600  logger.log(Level.INFO, "", ex);
601  }
602  }
603 
604 
605  try {
606  communicationArtifactsHelper.addAttachments(messageArtifact, new MessageAttachments(fileAttachments, Collections.emptyList()));
607  } catch (TskCoreException ex) {
608  postErrorMessage(
609  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.handleAttch.addAttachmentsErrorMsg"),
610  "");
611  logger.log(Level.INFO, "Failed to add attachments to email message.", ex);
612  }
613 
614  return files;
615  }
616 
621  private BlackboardArtifact associateAttachmentWithMesssge(BlackboardArtifact message, AbstractFile attachedFile) throws TskCoreException {
622  Collection<BlackboardAttribute> attributes = new ArrayList<>();
623  attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, EmailParserModuleFactory.getModuleName(), message.getArtifactID()));
624 
625  BlackboardArtifact bba = attachedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
626  bba.addAttributes(attributes); //write out to bb
627  return bba;
628  }
629 
637  private Set<String> findEmailAddresess(String input) {
638  Pattern p = Pattern.compile("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
639  Pattern.CASE_INSENSITIVE);
640  Matcher m = p.matcher(input);
641  Set<String> emailAddresses = new HashSet<>();
642  while (m.find()) {
643  emailAddresses.add( m.group());
644  }
645  return emailAddresses;
646  }
647 
656  @Messages({"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."})
657  private BlackboardArtifact addEmailArtifact(EmailMessage email, AbstractFile abstractFile) {
658  BlackboardArtifact bbart = null;
659  List<BlackboardAttribute> bbattributes = new ArrayList<>();
660  String to = email.getRecipients();
661  String cc = email.getCc();
662  String bcc = email.getBcc();
663  String from = email.getSender();
664  long dateL = email.getSentDate();
665  String headers = email.getHeaders();
666  String body = email.getTextBody();
667  String bodyHTML = email.getHtmlBody();
668  String rtf = email.getRtfBody();
669  String subject = email.getSubject();
670  long id = email.getId();
671  String localPath = email.getLocalPath();
672  String threadID = email.getMessageThreadID();
673 
674  List<String> senderAddressList = new ArrayList<>();
675  String senderAddress;
676  senderAddressList.addAll(findEmailAddresess(from));
677 
678  AccountFileInstance senderAccountInstance = null;
679 
680  if (senderAddressList.size() == 1) {
681  senderAddress = senderAddressList.get(0);
682  try {
683  senderAccountInstance = currentCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, EmailParserModuleFactory.getModuleName(), abstractFile);
684  }
685  catch(TskCoreException ex) {
686  logger.log(Level.WARNING, "Failed to create account for email address " + senderAddress, ex); //NON-NLS
687  }
688  }
689  else {
690  logger.log(Level.WARNING, "Failed to find sender address, from = {0}", from); //NON-NLS
691  }
692 
693  List<String> recipientAddresses = new ArrayList<>();
694  recipientAddresses.addAll(findEmailAddresess(to));
695  recipientAddresses.addAll(findEmailAddresess(cc));
696  recipientAddresses.addAll(findEmailAddresess(bcc));
697 
698  List<AccountFileInstance> recipientAccountInstances = new ArrayList<>();
699  recipientAddresses.forEach((addr) -> {
700  try {
701  AccountFileInstance recipientAccountInstance =
702  currentCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
703  EmailParserModuleFactory.getModuleName(), abstractFile);
704  recipientAccountInstances.add(recipientAccountInstance);
705  }
706  catch(TskCoreException ex) {
707  logger.log(Level.WARNING, "Failed to create account for email address " + addr, ex); //NON-NLS
708  }
709  });
710 
711  addArtifactAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
712  addArtifactAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
713  addArtifactAttribute(to, ATTRIBUTE_TYPE.TSK_EMAIL_TO, bbattributes);
714  addArtifactAttribute(subject, ATTRIBUTE_TYPE.TSK_SUBJECT, bbattributes);
715 
716  addArtifactAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, bbattributes);
717  addArtifactAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_SENT, bbattributes);
718 
719  addArtifactAttribute(body, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, bbattributes);
720 
721  addArtifactAttribute(((id < 0L) ? NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id)),
722  ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
723 
724  addArtifactAttribute(((localPath.isEmpty() == false) ? localPath : ""),
725  ATTRIBUTE_TYPE.TSK_PATH, bbattributes);
726 
727  addArtifactAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes);
728  addArtifactAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
729  addArtifactAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes);
730  addArtifactAttribute(threadID, ATTRIBUTE_TYPE.TSK_THREAD_ID, bbattributes);
731 
732 
733  try {
734 
735  bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
736  bbart.addAttributes(bbattributes);
737 
738  // Add account relationships
739  currentCase.getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
740 
741  try {
742  // index the artifact for keyword search
743  blackboard.postArtifact(bbart, EmailParserModuleFactory.getModuleName());
744  } catch (Blackboard.BlackboardException ex) {
745  logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getArtifactID(), ex); //NON-NLS
746  MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName());
747  }
748  } catch (TskCoreException | TskDataException ex) {
749  logger.log(Level.WARNING, null, ex);
750  }
751 
752  return bbart;
753  }
754 
762  static void addArtifactAttribute(String stringVal, BlackboardAttribute.Type attrType, Collection<BlackboardAttribute> bbattributes) {
763  if (stringVal.isEmpty() == false) {
764  bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), stringVal));
765  }
766  }
767 
775  static void addArtifactAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
776  if (stringVal.isEmpty() == false) {
777  bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), stringVal));
778  }
779  }
780 
788  static void addArtifactAttribute(long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
789  if (longVal > 0) {
790  bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), longVal));
791  }
792  }
793 
800  void postErrorMessage(String subj, String details) {
801  IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
802  services.postMessage(ingestMessage);
803  }
804 
810  IngestServices getServices() {
811  return services;
812  }
813 
814  @Override
815  public void shutDown() {
816  // nothing to shut down
817  }
818 
819 }
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
void processEmails(List< EmailMessage > partialEmailsForThreading, Iterator< EmailMessage > fullMessageIterator, AbstractFile abstractFile)
BlackboardArtifact addEmailArtifact(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)
BlackboardArtifact associateAttachmentWithMesssge(BlackboardArtifact message, AbstractFile attachedFile)
void addFilesToJob(List< AbstractFile > files)
void postMessage(final IngestMessage message)
void fireModuleContentEvent(ModuleContentEvent moduleContentEvent)
void processMboxFile(File file, AbstractFile abstractFile, String emailFolder)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
List< AbstractFile > handleAttachments(List< EmailMessage.Attachment > attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact)
static synchronized IngestServices getInstance()

Copyright © 2012-2020 Basis Technology. Generated on: Mon Jul 6 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.