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)