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;
 
   29 import org.
sleuthkit.datamodel.Blackboard.BlackboardException;
 
   33 import org.
sleuthkit.datamodel.InvalidAccountIDException;
 
   36 import org.
sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper;
 
   37 import org.
sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CallMediaType;
 
   38 import org.
sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CommunicationDirection;
 
   43 final class XRYCallsFileParser 
extends AbstractSingleEntityParser {
 
   45     private static final Logger logger = Logger.getLogger(XRYCallsFileParser.class.getName());
 
   52         NAME_MATCHED(
"name (matched)", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME),
 
   60         DELETED(
"deleted", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ISDELETED),
 
   65         NAME(
"name", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
 
   68         private final BlackboardAttribute.ATTRIBUTE_TYPE 
type;
 
   70         XryKey(String name, BlackboardAttribute.ATTRIBUTE_TYPE type) {
 
   75         public BlackboardAttribute.ATTRIBUTE_TYPE 
getType() {
 
   86             } 
catch (IllegalArgumentException ex) {
 
   99             String normalizedKey = key.trim().toLowerCase();
 
  101                 if (normalizedKey.equals(keyChoice.name)) {
 
  106             throw new IllegalArgumentException(String.format(
"Key [%s] was not found." 
  107                     + 
" All keys should be tested with contains.", key));
 
  129         public static boolean contains(String xryNamespace) {
 
  133             } 
catch (IllegalArgumentException ex) {
 
  147             String normalizedNamespace = xryNamespace.trim().toLowerCase();
 
  149                 if (normalizedNamespace.equals(keyChoice.name)) {
 
  154             throw new IllegalArgumentException(String.format(
"Key [%s] was not found." 
  155                     + 
" All keys should be tested with contains.", xryNamespace));
 
  160     boolean canProcess(XRYKeyValuePair pair) {
 
  161         return XryKey.
contains(pair.getKey());
 
  165     boolean isNamespace(String nameSpace) {
 
  166         return XryNamespace.contains(nameSpace);
 
  170     void makeArtifact(List<XRYKeyValuePair> keyValuePairs, Content parent, SleuthkitCase currentCase) 
throws TskCoreException, BlackboardException {
 
  173         String callerId = null;
 
  174         final Collection<String> calleeList = 
new ArrayList<>();
 
  175         CommunicationDirection direction = CommunicationDirection.UNKNOWN;
 
  177         final long endTime = 0L;
 
  178         final CallMediaType callType = CallMediaType.UNKNOWN;
 
  179         final Collection<BlackboardAttribute> otherAttributes = 
new ArrayList<>();
 
  181         for (XRYKeyValuePair pair : keyValuePairs) {
 
  182             XryKey xryKey = XryKey.fromDisplayName(pair.getKey());
 
  183             XryNamespace xryNamespace = XryNamespace.NONE;
 
  184             if (XryNamespace.contains(pair.getNamespace())) {
 
  185                 xryNamespace = XryNamespace.fromDisplayName(pair.getNamespace());
 
  191                     if(!XRYUtils.isPhoneValid(pair.getValue())) {
 
  196                     if (xryNamespace == XryNamespace.FROM || direction == CommunicationDirection.INCOMING) {
 
  197                         callerId = pair.getValue();
 
  198                     } 
else if (xryNamespace == XryNamespace.TO || direction == CommunicationDirection.OUTGOING) {
 
  199                         calleeList.add(pair.getValue());
 
  201                         otherAttributes.add(
new BlackboardAttribute(
 
  202                                 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
 
  203                                 PARSER_NAME, pair.getValue()));
 
  209                     if(!XRYUtils.isPhoneValid(pair.getValue())) {
 
  213                     calleeList.add(pair.getValue());
 
  216                     if(!XRYUtils.isPhoneValid(pair.getValue())) {
 
  220                     callerId = pair.getValue();
 
  225                         long dateTimeSinceEpoch = XRYUtils.calculateSecondsSinceEpoch(pair.getValue());
 
  226                         startTime = dateTimeSinceEpoch;
 
  227                     } 
catch (DateTimeParseException ex) {
 
  228                         logger.log(Level.WARNING, String.format(
"[XRY DSP] Assumption" 
  229                                 + 
" about the date time formatting of call logs is " 
  230                                 + 
"not right. Here is the value [ %s ]", pair.getValue()), ex);
 
  234                     String directionString = pair.getValue().toLowerCase();
 
  235                     if (directionString.equals(
"incoming")) {
 
  236                         direction = CommunicationDirection.INCOMING;
 
  238                         direction = CommunicationDirection.OUTGOING;
 
  242                     String typeString = pair.getValue();
 
  243                     if (typeString.equalsIgnoreCase(
"received")) {
 
  244                         direction = CommunicationDirection.INCOMING;
 
  245                     } 
else if (typeString.equalsIgnoreCase(
"dialed")) {
 
  246                         direction = CommunicationDirection.OUTGOING;
 
  252                     if (xryKey.getType() != null) {
 
  253                         otherAttributes.add(
new BlackboardAttribute(xryKey.getType(),
 
  254                                 PARSER_NAME, pair.getValue()));
 
  257                     logger.log(Level.INFO, String.format(
"[XRY DSP] Key value pair " 
  258                             + 
"(in brackets) [ %s ] was recognized but " 
  259                             + 
"more data or time is needed to finish implementation. Discarding... ",
 
  268         if (callerId == null && calleeList.isEmpty()
 
  269                 || direction == CommunicationDirection.INCOMING && callerId == null
 
  270                 || direction == CommunicationDirection.OUTGOING && calleeList.isEmpty()) {
 
  273             if (direction != CommunicationDirection.UNKNOWN) {
 
  274                 otherAttributes.add(
new BlackboardAttribute(
 
  275                         BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION,
 
  276                         PARSER_NAME, direction.getDisplayName()));
 
  279             if (startTime > 0L) {
 
  280                 otherAttributes.add(
new BlackboardAttribute(
 
  281                         BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START,
 
  282                         PARSER_NAME, startTime));
 
  289             if (callerId != null) {
 
  291                 currentCase.getCommunicationsManager().createAccountFileInstance(
 
  292                         Account.Type.PHONE, callerId, PARSER_NAME, parent);
 
  293                 } 
catch (InvalidAccountIDException ex) {
 
  294                    logger.log(Level.WARNING, String.format(
"Invalid account identifier %s", callerId), ex);
 
  297                 otherAttributes.add(
new BlackboardAttribute(
 
  298                         BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
 
  299                         PARSER_NAME, callerId));
 
  302             for (String phone : calleeList) {
 
  304                 currentCase.getCommunicationsManager().createAccountFileInstance(
 
  305                         Account.Type.PHONE, phone, PARSER_NAME, parent);
 
  306                 } 
catch (InvalidAccountIDException ex) {
 
  307                     logger.log(Level.WARNING, String.format(
"Invalid account identifier %s", phone), ex);
 
  311                 otherAttributes.add(
new BlackboardAttribute(
 
  312                         BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
 
  313                         PARSER_NAME, phone));
 
  316             if (!otherAttributes.isEmpty()) {
 
  317                 BlackboardArtifact artifact = parent.newDataArtifact(
new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG), otherAttributes);
 
  319                 currentCase.getBlackboard().postArtifact(artifact, PARSER_NAME);
 
  324             CommunicationArtifactsHelper helper = 
new CommunicationArtifactsHelper(
 
  325                     currentCase, PARSER_NAME, parent, Account.Type.PHONE);
 
  327             helper.addCalllog(direction, callerId, calleeList, startTime,
 
  328                     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)