19 package org.sleuthkit.autopsy.datasourceprocessors.xry;
 
   21 import java.time.format.DateTimeParseException;
 
   22 import java.util.ArrayList;
 
   23 import java.util.Collection;
 
   24 import java.util.List;
 
   25 import java.util.logging.Level;
 
   28 import org.
sleuthkit.datamodel.Blackboard.BlackboardException;
 
   32 import org.
sleuthkit.datamodel.InvalidAccountIDException;
 
   35 import org.
sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper;
 
   36 import org.
sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CallMediaType;
 
   37 import org.
sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CommunicationDirection;
 
   42 final class XRYCallsFileParser 
extends AbstractSingleEntityParser {
 
   44     private static final Logger logger = Logger.getLogger(XRYCallsFileParser.class.getName());
 
   51         NAME_MATCHED(
"name (matched)", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME),
 
   59         DELETED(
"deleted", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ISDELETED),
 
   64         NAME(
"name", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
 
   67         private final BlackboardAttribute.ATTRIBUTE_TYPE 
type;
 
   69         XryKey(String name, BlackboardAttribute.ATTRIBUTE_TYPE type) {
 
   74         public BlackboardAttribute.ATTRIBUTE_TYPE 
getType() {
 
   85             } 
catch (IllegalArgumentException ex) {
 
   98             String normalizedKey = key.trim().toLowerCase();
 
  100                 if (normalizedKey.equals(keyChoice.name)) {
 
  105             throw new IllegalArgumentException(String.format(
"Key [%s] was not found." 
  106                     + 
" All keys should be tested with contains.", key));
 
  128         public static boolean contains(String xryNamespace) {
 
  132             } 
catch (IllegalArgumentException ex) {
 
  146             String normalizedNamespace = xryNamespace.trim().toLowerCase();
 
  148                 if (normalizedNamespace.equals(keyChoice.name)) {
 
  153             throw new IllegalArgumentException(String.format(
"Key [%s] was not found." 
  154                     + 
" All keys should be tested with contains.", xryNamespace));
 
  159     boolean canProcess(XRYKeyValuePair pair) {
 
  160         return XryKey.
contains(pair.getKey());
 
  164     boolean isNamespace(String nameSpace) {
 
  165         return XryNamespace.contains(nameSpace);
 
  169     void makeArtifact(List<XRYKeyValuePair> keyValuePairs, Content parent, SleuthkitCase currentCase) 
throws TskCoreException, BlackboardException {
 
  172         String callerId = null;
 
  173         final Collection<String> calleeList = 
new ArrayList<>();
 
  174         CommunicationDirection direction = CommunicationDirection.UNKNOWN;
 
  176         final long endTime = 0L;
 
  177         final CallMediaType callType = CallMediaType.UNKNOWN;
 
  178         final Collection<BlackboardAttribute> otherAttributes = 
new ArrayList<>();
 
  180         for (XRYKeyValuePair pair : keyValuePairs) {
 
  181             XryKey xryKey = XryKey.fromDisplayName(pair.getKey());
 
  182             XryNamespace xryNamespace = XryNamespace.NONE;
 
  183             if (XryNamespace.contains(pair.getNamespace())) {
 
  184                 xryNamespace = XryNamespace.fromDisplayName(pair.getNamespace());
 
  190                     if (!XRYUtils.isPhoneValid(pair.getValue())) {
 
  195                     if (xryNamespace == XryNamespace.FROM || direction == CommunicationDirection.INCOMING) {
 
  196                         callerId = pair.getValue();
 
  197                     } 
else if (xryNamespace == XryNamespace.TO || direction == CommunicationDirection.OUTGOING) {
 
  198                         calleeList.add(pair.getValue());
 
  200                         otherAttributes.add(
new BlackboardAttribute(
 
  201                                 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
 
  202                                 PARSER_NAME, pair.getValue()));
 
  208                     if (!XRYUtils.isPhoneValid(pair.getValue())) {
 
  212                     calleeList.add(pair.getValue());
 
  215                     if (!XRYUtils.isPhoneValid(pair.getValue())) {
 
  219                     callerId = pair.getValue();
 
  224                     long dateTimeSinceEpoch = XRYUtils.calculateSecondsSinceEpoch(pair.getValue());
 
  225                     startTime = dateTimeSinceEpoch;
 
  226                 } 
catch (DateTimeParseException ex) {
 
  227                     logger.log(Level.WARNING, String.format(
"[XRY DSP] Assumption" 
  228                             + 
" about the date time formatting of call logs is " 
  229                             + 
"not right. Here is the value [ %s ]", pair.getValue()), ex);
 
  233                     String directionString = pair.getValue().toLowerCase();
 
  234                     if (directionString.equals(
"incoming")) {
 
  235                         direction = CommunicationDirection.INCOMING;
 
  237                         direction = CommunicationDirection.OUTGOING;
 
  241                     String typeString = pair.getValue();
 
  242                     if (typeString.equalsIgnoreCase(
"received")) {
 
  243                         direction = CommunicationDirection.INCOMING;
 
  244                     } 
else if (typeString.equalsIgnoreCase(
"dialed")) {
 
  245                         direction = CommunicationDirection.OUTGOING;
 
  251                     if (xryKey.getType() != null) {
 
  252                         otherAttributes.add(
new BlackboardAttribute(xryKey.getType(),
 
  253                                 PARSER_NAME, pair.getValue()));
 
  256                     logger.log(Level.INFO, String.format(
"[XRY DSP] Key value pair " 
  257                             + 
"(in brackets) [ %s ] was recognized but " 
  258                             + 
"more data or time is needed to finish implementation. Discarding... ",
 
  266         if (callerId == null && calleeList.isEmpty()
 
  267                 || direction == CommunicationDirection.INCOMING && callerId == null
 
  268                 || direction == CommunicationDirection.OUTGOING && calleeList.isEmpty()) {
 
  271             if (direction != CommunicationDirection.UNKNOWN) {
 
  272                 otherAttributes.add(
new BlackboardAttribute(
 
  273                         BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION,
 
  274                         PARSER_NAME, direction.getDisplayName()));
 
  277             if (startTime > 0L) {
 
  278                 otherAttributes.add(
new BlackboardAttribute(
 
  279                         BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START,
 
  280                         PARSER_NAME, startTime));
 
  287             if (callerId != null) {
 
  289                     currentCase.getCommunicationsManager().createAccountFileInstance(
 
  290                             Account.Type.PHONE, callerId, PARSER_NAME, parent, null, null);
 
  291                 } 
catch (InvalidAccountIDException ex) {
 
  292                     logger.log(Level.WARNING, String.format(
"Invalid account identifier %s", callerId), ex);
 
  295                 otherAttributes.add(
new BlackboardAttribute(
 
  296                         BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
 
  297                         PARSER_NAME, callerId));
 
  300             for (String phone : calleeList) {
 
  302                     currentCase.getCommunicationsManager().createAccountFileInstance(
 
  303                             Account.Type.PHONE, phone, PARSER_NAME, parent, null, null);
 
  304                 } 
catch (InvalidAccountIDException ex) {
 
  305                     logger.log(Level.WARNING, String.format(
"Invalid account identifier %s", phone), ex);
 
  308                 otherAttributes.add(
new BlackboardAttribute(
 
  309                         BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
 
  310                         PARSER_NAME, phone));
 
  313             if (!otherAttributes.isEmpty()) {
 
  314                 BlackboardArtifact artifact = parent.newDataArtifact(
new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG), otherAttributes);
 
  316                 currentCase.getBlackboard().postArtifact(artifact, PARSER_NAME, null);
 
  321             CommunicationArtifactsHelper helper = 
new CommunicationArtifactsHelper(
 
  322                     currentCase, PARSER_NAME, parent, Account.Type.PHONE, null);
 
  324             helper.addCalllog(direction, callerId, calleeList, startTime,
 
  325                     endTime, callType, otherAttributes);
 
BlackboardAttribute.ATTRIBUTE_TYPE getType()
static boolean contains(String xryNamespace)
final BlackboardAttribute.ATTRIBUTE_TYPE type
static XryKey fromDisplayName(String key)
static XryNamespace fromDisplayName(String xryNamespace)
XryKey(String name, BlackboardAttribute.ATTRIBUTE_TYPE type)
XryNamespace(String name)
static boolean contains(String key)