Sleuth Kit Java Bindings (JNI)  4.6
Java bindings for using The Sleuth Kit
CommunicationArtifactsHelper.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2019-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.datamodel.blackboardutils;
20 
21 import com.google.gson.Gson;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.List;
27 import org.apache.commons.lang3.StringUtils;
44 
65 public final class CommunicationArtifactsHelper extends ArtifactHelperBase {
66 
70  public enum MessageReadStatus {
71 
72  UNKNOWN("Unknown"),
73  UNREAD("Unread"),
74  READ("Read");
75 
76  private final String msgReadStr;
77 
78  MessageReadStatus(String readStatus) {
79  this.msgReadStr = readStatus;
80  }
81 
82  public String getDisplayName() {
83  return msgReadStr;
84  }
85  }
86 
90  public enum CommunicationDirection {
91  UNKNOWN("Unknown"),
92  INCOMING("Incoming"),
93  OUTGOING("Outgoing");
94 
95  private final String dirStr;
96 
97  CommunicationDirection(String dir) {
98  this.dirStr = dir;
99  }
100 
101  public String getDisplayName() {
102  return dirStr;
103  }
104  }
105 
109  public enum CallMediaType {
110  UNKNOWN("Unknown"),
111  AUDIO("Audio"), // Audio only call
112  VIDEO("Video"); // Video/multimedia call
113 
114  private final String typeStr;
115 
116  CallMediaType(String type) {
117  this.typeStr = type;
118  }
119 
120  public String getDisplayName() {
121  return typeStr;
122  }
123  }
124 
125  // 'self' account for the application being processed by the module.
126  private final Account.Type selfAccountType;
127  private final String selfAccountId;
128 
129  private AccountFileInstance selfAccountInstance = null;
130 
131  // Type of accounts to be created for the module using this helper.
132  private final Account.Type moduleAccountsType;
133 
152  String moduleName, Content srcContent, Account.Type accountsType) throws TskCoreException {
153 
154  super(caseDb, moduleName, srcContent);
155 
156  this.moduleAccountsType = accountsType;
157  this.selfAccountType = Account.Type.DEVICE;
158  this.selfAccountId = ((DataSource) getContent().getDataSource()).getDeviceId();
159  }
160 
180  public CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType, Account.Type selfAccountType, String selfAccountId) throws TskCoreException {
181 
182  super(caseDb, moduleName, srcContent);
183 
184  this.moduleAccountsType = accountsType;
185  this.selfAccountType = selfAccountType;
186  this.selfAccountId = selfAccountId;
187  }
188 
210  public BlackboardArtifact addContact(String contactName,
211  String phoneNumber, String homePhoneNumber,
212  String mobilePhoneNumber, String emailAddr) throws TskCoreException, BlackboardException {
213  return addContact(contactName, phoneNumber,
214  homePhoneNumber, mobilePhoneNumber, emailAddr,
215  Collections.emptyList());
216  }
217 
243  public BlackboardArtifact addContact(String contactName,
244  String phoneNumber, String homePhoneNumber,
245  String mobilePhoneNumber, String emailAddr,
246  Collection<BlackboardAttribute> additionalAttributes) throws TskCoreException, BlackboardException {
247 
248  // Contact name must be provided
249  if (StringUtils.isEmpty(contactName)) {
250  throw new IllegalArgumentException("Contact name must be specified.");
251  }
252 
253  // check if the caller has included any phone/email/id in addtional attributes
254  boolean hasAnyIdAttribute = false;
255  if (additionalAttributes != null) {
256  for (BlackboardAttribute attr : additionalAttributes) {
257  if ((attr.getAttributeType().getTypeName().startsWith("TSK_PHONE"))
258  || (attr.getAttributeType().getTypeName().startsWith("TSK_EMAIL"))
259  || (attr.getAttributeType().getTypeName().startsWith("TSK_ID"))) {
260  hasAnyIdAttribute = true;
261  break;
262  }
263  }
264  }
265 
266  // At least one phone number or email address
267  // or an optional attribute with phone/email/id must be provided
268  if (StringUtils.isEmpty(phoneNumber) && StringUtils.isEmpty(homePhoneNumber)
269  && StringUtils.isEmpty(mobilePhoneNumber) && StringUtils.isEmpty(emailAddr)
270  && (!hasAnyIdAttribute)) {
271  throw new IllegalArgumentException("At least one phone number or email address or an id must be provided.");
272  }
273 
274  BlackboardArtifact contactArtifact;
275  Collection<BlackboardAttribute> attributes = new ArrayList<>();
276 
277  // create TSK_CONTACT artifact
278  contactArtifact = getContent().newArtifact(ARTIFACT_TYPE.TSK_CONTACT);
279 
280  // construct attributes
281  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, getModuleName(), contactName));
282 
283  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, phoneNumber, attributes);
284  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME, homePhoneNumber, attributes);
285  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE, mobilePhoneNumber, attributes);
286  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_EMAIL, emailAddr, attributes);
287 
288  // add attributes
289  attributes.addAll(additionalAttributes);
290  contactArtifact.addAttributes(attributes);
291 
292  // create an account for each specified contact method, and a relationship with self account
293  createContactMethodAccountAndRelationship(Account.Type.PHONE, phoneNumber, contactArtifact, 0);
294  createContactMethodAccountAndRelationship(Account.Type.PHONE, homePhoneNumber, contactArtifact, 0);
295  createContactMethodAccountAndRelationship(Account.Type.PHONE, mobilePhoneNumber, contactArtifact, 0);
296  createContactMethodAccountAndRelationship(Account.Type.EMAIL, emailAddr, contactArtifact, 0);
297 
298  // if the additional attribute list has any phone/email/id attributes, create accounts & relationships for those.
299  if ((additionalAttributes != null) && hasAnyIdAttribute) {
300  for (BlackboardAttribute bba : additionalAttributes) {
301  if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
302  createContactMethodAccountAndRelationship(Account.Type.PHONE, bba.getValueString(), contactArtifact, 0);
303  } else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
304  createContactMethodAccountAndRelationship(Account.Type.EMAIL, bba.getValueString(), contactArtifact, 0);
305  } else if (bba.getAttributeType().getTypeName().startsWith("TSK_ID")) {
306  createContactMethodAccountAndRelationship(this.moduleAccountsType, bba.getValueString(), contactArtifact, 0);
307  }
308  }
309  }
310 
311  // post artifact
312  getSleuthkitCase().getBlackboard().postArtifact(contactArtifact, getModuleName());
313 
314  return contactArtifact;
315  }
316 
324  private void createContactMethodAccountAndRelationship(Account.Type accountType,
325  String accountUniqueID, BlackboardArtifact sourceArtifact,
326  long dateTime) throws TskCoreException {
327 
328  // Find/Create an account instance for each of the contact method
329  // Create a relationship between selfAccount and contactAccount
330  if (!StringUtils.isEmpty(accountUniqueID)) {
331  AccountFileInstance contactAccountInstance = createAccountInstance(accountType, accountUniqueID);
332 
333  // Create a relationship between self account and the contact account
334  try {
335  getSleuthkitCase().getCommunicationsManager().addRelationships(getSelfAccountInstance(),
336  Collections.singletonList(contactAccountInstance), sourceArtifact, Relationship.Type.CONTACT, dateTime);
337  } catch (TskDataException ex) {
338  throw new TskCoreException(String.format("Failed to create relationship between account = %s and account = %s.",
339  getSelfAccountInstance().getAccount(), contactAccountInstance.getAccount()), ex);
340  }
341  }
342  }
343 
356  private AccountFileInstance createAccountInstance(Account.Type accountType, String accountUniqueID) throws TskCoreException {
357  return getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(accountType, accountUniqueID, getModuleName(), getContent());
358  }
359 
382  String messageType,
383  CommunicationDirection direction,
384  String senderId,
385  String recipientId,
386  long dateTime, MessageReadStatus readStatus,
387  String subject, String messageText, String threadId) throws TskCoreException, BlackboardException {
388  return addMessage(messageType, direction,
389  senderId, recipientId, dateTime, readStatus,
390  subject, messageText, threadId,
391  Collections.emptyList());
392  }
393 
416  public BlackboardArtifact addMessage(String messageType,
417  CommunicationDirection direction,
418  String senderId,
419  String recipientId,
420  long dateTime, MessageReadStatus readStatus, String subject,
421  String messageText, String threadId,
422  Collection<BlackboardAttribute> otherAttributesList) throws TskCoreException, BlackboardException {
423 
424  return addMessage(messageType, direction,
425  senderId,
426  Arrays.asList(recipientId),
427  dateTime, readStatus,
428  subject, messageText, threadId,
429  otherAttributesList);
430  }
431 
454  public BlackboardArtifact addMessage(String messageType,
455  CommunicationDirection direction,
456  String senderId,
457  List<String> recipientIdsList,
458  long dateTime, MessageReadStatus readStatus,
459  String subject, String messageText, String threadId) throws TskCoreException, BlackboardException {
460  return addMessage(messageType, direction,
461  senderId, recipientIdsList,
462  dateTime, readStatus,
463  subject, messageText, threadId,
464  Collections.emptyList());
465  }
466 
489  public BlackboardArtifact addMessage(String messageType,
490  CommunicationDirection direction,
491  String senderId,
492  List<String> recipientIdsList,
493  long dateTime, MessageReadStatus readStatus,
494  String subject, String messageText,
495  String threadId,
496  Collection<BlackboardAttribute> otherAttributesList) throws TskCoreException, BlackboardException {
497 
498  // Created message artifact.
499  BlackboardArtifact msgArtifact;
500  Collection<BlackboardAttribute> attributes = new ArrayList<>();
501 
502  // create TSK_MESSAGE artifact
503  msgArtifact = getContent().newArtifact(ARTIFACT_TYPE.TSK_MESSAGE);
504 
505  // construct attributes
506  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, getModuleName(), messageType));
507  addAttributeIfNotZero(ATTRIBUTE_TYPE.TSK_DATETIME, dateTime, attributes);
508 
509  addMessageReadStatusIfKnown(readStatus, attributes);
510  addCommDirectionIfKnown(direction, attributes);
511 
512  // set sender attribute and create sender account
513  AccountFileInstance senderAccountInstance;
514  if (StringUtils.isEmpty(senderId)) {
515  senderAccountInstance = getSelfAccountInstance();
516  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, getSelfAccountInstance().getAccount().getTypeSpecificID(), attributes);
517  } else {
518  senderAccountInstance = createAccountInstance(moduleAccountsType, senderId);
519  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, senderId, attributes);
520  }
521 
522  // set recipient attribute and create recipient accounts
523  List<AccountFileInstance> recipientAccountsList = new ArrayList<>();
524  String recipientsStr = "";
525  if (recipientIdsList != null) {
526  for (String recipient : recipientIdsList) {
527  if (!StringUtils.isEmpty(recipient)) {
528  recipientAccountsList.add(createAccountInstance(moduleAccountsType, recipient));
529  }
530  }
531  // Create a comma separated string of recipients
532  recipientsStr = addressListToString(recipientIdsList);
533  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, recipientsStr, attributes);
534  }
535 
536  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_SUBJECT, subject, attributes);
537  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_TEXT, messageText, attributes);
538  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_THREAD_ID, threadId, attributes);
539 
540  // add attributes to artifact
541  attributes.addAll(otherAttributesList);
542  msgArtifact.addAttributes(attributes);
543 
544  // create sender/recipient relationships
545  try {
546  getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance,
547  recipientAccountsList, msgArtifact, Relationship.Type.MESSAGE, dateTime);
548  } catch (TskDataException ex) {
549  throw new TskCoreException(String.format("Failed to create Message relationships between sender account = %s and recipients = %s.",
550  senderAccountInstance.getAccount().getTypeSpecificID(), recipientsStr), ex);
551  }
552 
553  // post artifact
554  getSleuthkitCase().getBlackboard().postArtifact(msgArtifact, getModuleName());
555 
556  // return the artifact
557  return msgArtifact;
558  }
559 
583  String callerId, String calleeId,
584  long startDateTime, long endDateTime, CallMediaType mediaType) throws TskCoreException, BlackboardException {
585  return addCalllog(direction, callerId, calleeId,
586  startDateTime, endDateTime, mediaType,
587  Collections.emptyList());
588  }
589 
614  String callerId,
615  String calleeId,
616  long startDateTime, long endDateTime,
617  CallMediaType mediaType,
618  Collection<BlackboardAttribute> otherAttributesList) throws TskCoreException, BlackboardException {
619  return addCalllog(direction,
620  callerId,
621  Arrays.asList(calleeId),
622  startDateTime, endDateTime,
623  mediaType,
624  otherAttributesList);
625  }
626 
650  String callerId,
651  Collection<String> calleeIdsList,
652  long startDateTime, long endDateTime,
653  CallMediaType mediaType) throws TskCoreException, BlackboardException {
654 
655  return addCalllog(direction, callerId, calleeIdsList,
656  startDateTime, endDateTime,
657  mediaType,
658  Collections.emptyList());
659  }
660 
685  String callerId,
686  Collection<String> calleeIdsList,
687  long startDateTime, long endDateTime,
688  CallMediaType mediaType,
689  Collection<BlackboardAttribute> otherAttributesList) throws TskCoreException, BlackboardException {
690 
691  // Either caller id or a callee id must be provided.
692  if (StringUtils.isEmpty(callerId) && (isEffectivelyEmpty(calleeIdsList))) {
693  throw new IllegalArgumentException("Either a caller id, or at least one callee id must be provided for a call log.");
694  }
695 
696  BlackboardArtifact callLogArtifact;
697  Collection<BlackboardAttribute> attributes = new ArrayList<>();
698 
699  // Create TSK_CALLLOG artifact
700  callLogArtifact = getContent().newArtifact(ARTIFACT_TYPE.TSK_CALLLOG);
701 
702  // Add basic attributes
703  addAttributeIfNotZero(ATTRIBUTE_TYPE.TSK_DATETIME_START, startDateTime, attributes);
704  addAttributeIfNotZero(ATTRIBUTE_TYPE.TSK_DATETIME_END, endDateTime, attributes);
705  addCommDirectionIfKnown(direction, attributes);
706 
707  // set FROM attribute and create a caller account
708  AccountFileInstance callerAccountInstance;
709  if (StringUtils.isEmpty(callerId)) {
710  // for an Outgoing call, if no caller is specified, assume self account is the caller
711  if (direction == CommunicationDirection.OUTGOING) {
712  callerAccountInstance = getSelfAccountInstance();
713  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, getSelfAccountInstance().getAccount().getTypeSpecificID(), attributes);
714  } else { // incoming call without a caller id
715  throw new IllegalArgumentException("Caller Id not provided for incoming call.");
716  }
717  } else {
718  callerAccountInstance = createAccountInstance(moduleAccountsType, callerId);
719  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, callerId, attributes);
720  }
721 
722  // Create a comma separated string of callee
723  List<AccountFileInstance> recipientAccountsList = new ArrayList<>();
724  String calleesStr = "";
725  if (!isEffectivelyEmpty(calleeIdsList)) {
726  calleesStr = addressListToString(calleeIdsList);
727  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, calleesStr, attributes);
728 
729  for (String callee : calleeIdsList) {
730  if (!StringUtils.isEmpty(callee)) {
731  recipientAccountsList.add(createAccountInstance(moduleAccountsType, callee));
732  }
733  }
734  } else {
735  // For incoming call, if no callee specified, assume self account is callee
736  if (direction == CommunicationDirection.INCOMING) {
737  addAttributeIfNotNull(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, getSelfAccountInstance().getAccount().getTypeSpecificID(), attributes);
738  recipientAccountsList.add(getSelfAccountInstance());
739  } else { // outgoing call without any callee
740  throw new IllegalArgumentException("Callee not provided for an outgoing call.");
741  }
742  }
743 
744  // add attributes to artifact
745  attributes.addAll(otherAttributesList);
746  callLogArtifact.addAttributes(attributes);
747 
748  // create relationships between caller/callees
749  try {
750  getSleuthkitCase().getCommunicationsManager().addRelationships(callerAccountInstance,
751  recipientAccountsList, callLogArtifact, Relationship.Type.CALL_LOG, startDateTime);
752  } catch (TskDataException ex) {
753  throw new TskCoreException(String.format("Failed to create Call log relationships between caller account = %s and callees = %s.",
754  callerAccountInstance.getAccount(), calleesStr), ex);
755  }
756 
757  // post artifact
758  getSleuthkitCase().getBlackboard().postArtifact(callLogArtifact, getModuleName());
759 
760  // return the artifact
761  return callLogArtifact;
762  }
763 
772  public void addAttachments(BlackboardArtifact message, MessageAttachments attachments) throws TskCoreException {
773 
774  // Convert the MessageAttachments object to JSON string
775  Gson gson = new Gson();
776  String attachmentsJson = gson.toJson(attachments);
777 
778  // Create attribute
779  message.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS, getModuleName(), attachmentsJson));
780 
781  // Associate each attachment file with the message.
782  Collection<FileAttachment> fileAttachments = attachments.getFileAttachments();
783  for (FileAttachment fileAttachment : fileAttachments) {
784  long attachedFileObjId = fileAttachment.getObjectId();
785  if (attachedFileObjId >= 0) {
786  AbstractFile attachedFile = message.getSleuthkitCase().getAbstractFileById(attachedFileObjId);
787  associateAttachmentWithMessage(message, attachedFile);
788  }
789  }
790  }
791 
804  private BlackboardArtifact associateAttachmentWithMessage(BlackboardArtifact message, AbstractFile attachedFile) throws TskCoreException {
805  Collection<BlackboardAttribute> attributes = new ArrayList<>();
806  attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, this.getModuleName(), message.getArtifactID()));
807 
809  bba.addAttributes(attributes); //write out to bb
810  return bba;
811  }
812 
816  private String addressListToString(Collection<String> addressList) {
817 
818  String toAddresses = "";
819  if (addressList != null && (!addressList.isEmpty())) {
820  StringBuilder toAddressesSb = new StringBuilder();
821  for (String address : addressList) {
822  if (!StringUtils.isEmpty(address)) {
823  toAddressesSb = toAddressesSb.length() > 0 ? toAddressesSb.append(", ").append(address) : toAddressesSb.append(address);
824  }
825  }
826  toAddresses = toAddressesSb.toString();
827  }
828 
829  return toAddresses;
830  }
831 
841  private boolean isEffectivelyEmpty(Collection<String> idList) {
842 
843  if (idList == null || idList.isEmpty()) {
844  return true;
845  }
846 
847  for (String id : idList) {
848  if (!StringUtils.isEmpty(id)) {
849  return false;
850  }
851  }
852 
853  return true;
854 
855  }
856 
860  private void addCommDirectionIfKnown(CommunicationDirection direction, Collection<BlackboardAttribute> attributes) {
861  if (direction != CommunicationDirection.UNKNOWN) {
862  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, getModuleName(), direction.getDisplayName()));
863  }
864  }
865 
869  private void addMessageReadStatusIfKnown(MessageReadStatus readStatus, Collection<BlackboardAttribute> attributes) {
870  if (readStatus != MessageReadStatus.UNKNOWN) {
871  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_READ_STATUS, getModuleName(), (readStatus == MessageReadStatus.READ) ? 1 : 0));
872  }
873  }
874 
881  private synchronized AccountFileInstance getSelfAccountInstance() throws TskCoreException {
882  if (selfAccountInstance == null) {
883  selfAccountInstance = getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(selfAccountType, selfAccountId, this.getModuleName(), getContent());
884  }
885  return selfAccountInstance;
886  }
887 }
BlackboardArtifact addMessage(String messageType, CommunicationDirection direction, String senderId, List< String > recipientIdsList, long dateTime, MessageReadStatus readStatus, String subject, String messageText, String threadId, Collection< BlackboardAttribute > otherAttributesList)
BlackboardArtifact addContact(String contactName, String phoneNumber, String homePhoneNumber, String mobilePhoneNumber, String emailAddr)
void addAttributes(Collection< BlackboardAttribute > attributes)
CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType)
BlackboardArtifact addContact(String contactName, String phoneNumber, String homePhoneNumber, String mobilePhoneNumber, String emailAddr, Collection< BlackboardAttribute > additionalAttributes)
static final Account.Type PHONE
Definition: Account.java:49
BlackboardArtifact addMessage(String messageType, CommunicationDirection direction, String senderId, String recipientId, long dateTime, MessageReadStatus readStatus, String subject, String messageText, String threadId)
BlackboardArtifact newArtifact(int artifactTypeID)
BlackboardArtifact addMessage(String messageType, CommunicationDirection direction, String senderId, String recipientId, long dateTime, MessageReadStatus readStatus, String subject, String messageText, String threadId, Collection< BlackboardAttribute > otherAttributesList)
static final Relationship.Type CALL_LOG
BlackboardArtifact addCalllog(CommunicationDirection direction, String callerId, Collection< String > calleeIdsList, long startDateTime, long endDateTime, CallMediaType mediaType, Collection< BlackboardAttribute > otherAttributesList)
BlackboardArtifact addCalllog(CommunicationDirection direction, String callerId, Collection< String > calleeIdsList, long startDateTime, long endDateTime, CallMediaType mediaType)
CommunicationArtifactsHelper(SleuthkitCase caseDb, String moduleName, Content srcContent, Account.Type accountsType, Account.Type selfAccountType, String selfAccountId)
BlackboardArtifact addCalllog(CommunicationDirection direction, String callerId, String calleeId, long startDateTime, long endDateTime, CallMediaType mediaType, Collection< BlackboardAttribute > otherAttributesList)
static final Account.Type DEVICE
Definition: Account.java:48
static final Relationship.Type MESSAGE
BlackboardArtifact addMessage(String messageType, CommunicationDirection direction, String senderId, List< String > recipientIdsList, long dateTime, MessageReadStatus readStatus, String subject, String messageText, String threadId)
static final Relationship.Type CONTACT
BlackboardArtifact addCalllog(CommunicationDirection direction, String callerId, String calleeId, long startDateTime, long endDateTime, CallMediaType mediaType)
void addAttachments(BlackboardArtifact message, MessageAttachments attachments)
static final Account.Type EMAIL
Definition: Account.java:50

Copyright © 2011-2018 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.