19 package org.sleuthkit.datamodel;
 
   21 import java.sql.PreparedStatement;
 
   22 import java.sql.ResultSet;
 
   23 import java.sql.SQLException;
 
   24 import java.sql.Statement;
 
   25 import java.util.ArrayList;
 
   26 import java.util.Arrays;
 
   27 import java.util.Collections;
 
   28 import java.util.HashMap;
 
   29 import java.util.HashSet;
 
   30 import java.util.List;
 
   33 import java.util.concurrent.ConcurrentHashMap;
 
   34 import java.util.logging.Level;
 
   35 import java.util.logging.Logger;
 
   53         private final Map<
Account.
Type, Integer> accountTypeToTypeIdMap
 
   54                         = 
new ConcurrentHashMap<>();
 
   55         private final Map<String, 
Account.
Type> typeNameToAccountTypeMap
 
   56                         = 
new ConcurrentHashMap<>();
 
   59         private static final Set<Integer> RELATIONSHIP_ARTIFACT_TYPE_IDS = 
new HashSet<Integer>(Arrays.asList(
 
   65         private static final String RELATIONSHIP_ARTIFACT_TYPE_IDS_CSV_STR = CommManagerSqlStringUtils.buildCSVString(RELATIONSHIP_ARTIFACT_TYPE_IDS);
 
   88                 try (CaseDbConnection connection = db.getConnection();
 
   89                                 Statement statement = connection.createStatement();) {
 
   91                         int count = readAccountTypes();
 
   96                                                 statement.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + type.getTypeName() + 
"', '" + type.getDisplayName() + 
"')"); 
 
   97                                         } 
catch (SQLException ex) {
 
   98                                                 try (ResultSet resultSet = connection.executeQuery(statement, 
"SELECT COUNT(*) AS count FROM account_types WHERE type_name = '" + type.getTypeName() + 
"'")) { 
 
  100                                                         if (resultSet.getLong(
"count") == 0) {
 
  106                                         try (ResultSet rs2 = connection.executeQuery(statement, 
"SELECT account_type_id FROM account_types WHERE type_name = '" + type.getTypeName() + 
"'")) { 
 
  108                                                 int typeID = rs2.getInt(
"account_type_id");
 
  111                                                 this.accountTypeToTypeIdMap.put(accountType, typeID);
 
  112                                                 this.typeNameToAccountTypeMap.put(type.getTypeName(), accountType);
 
  116                 } 
catch (SQLException ex) {
 
  117                         LOGGER.log(Level.SEVERE, 
"Failed to add row to account_types", ex);
 
  132                 CaseDbConnection connection = null;
 
  133                 Statement statement = null;
 
  134                 ResultSet resultSet = null;
 
  139                         connection = db.getConnection();
 
  140                         statement = connection.createStatement();
 
  143                         resultSet = connection.executeQuery(statement, 
"SELECT COUNT(*) AS count FROM account_types"); 
 
  145                         if (resultSet.getLong(
"count") > 0) {
 
  148                                 resultSet = connection.executeQuery(statement, 
"SELECT * FROM account_types");
 
  149                                 while (resultSet.next()) {
 
  150                                         Account.
Type accountType = 
new Account.
Type(resultSet.getString(
"type_name"), resultSet.getString(
"display_name"));
 
  151                                         this.accountTypeToTypeIdMap.put(accountType, resultSet.getInt(
"account_type_id"));
 
  152                                         this.typeNameToAccountTypeMap.put(accountType.getTypeName(), accountType);
 
  154                                 count = this.typeNameToAccountTypeMap.size();
 
  157                 } 
catch (SQLException ex) {
 
  160                         closeResultSet(resultSet);
 
  161                         closeStatement(statement);
 
  162                         closeConnection(connection);
 
  195                 if (this.accountTypeToTypeIdMap.containsKey(accountType)) {
 
  203                         s = trans.getConnection().createStatement();
 
  204                         rs = trans.getConnection().executeQuery(s, 
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName + 
"'"); 
 
  208                                 s.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + accountTypeName + 
"', '" + displayName + 
"')"); 
 
  211                                 rs = trans.getConnection().executeQuery(s, 
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName + 
"'"); 
 
  214                                 int typeID = rs.getInt(
"account_type_id");
 
  215                                 accountType = 
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
 
  217                                 this.accountTypeToTypeIdMap.put(accountType, typeID);
 
  218                                 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
 
  224                                 int typeID = rs.getInt(
"account_type_id");
 
  226                                 accountType = 
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
 
  227                                 this.accountTypeToTypeIdMap.put(accountType, typeID);
 
  231                 } 
catch (SQLException ex) {
 
  267                 Account account = getOrCreateAccount(accountType, normalizeAccountID(accountType, accountUniqueID));
 
  275                 BlackboardArtifact accountArtifact = getOrCreateAccountFileInstanceArtifact(accountType, normalizeAccountID(accountType, accountUniqueID), moduleName, sourceFile, attributes, ingestJobId);
 
  332                 try (CaseDbConnection connection = db.getConnection();
 
  333                                 Statement s = connection.createStatement();
 
  334                                 ResultSet rs = connection.executeQuery(s, 
"SELECT * FROM accounts WHERE account_type_id = " + getAccountTypeId(accountType)
 
  335                                                 + 
" AND account_unique_identifier = '" + normalizeAccountID(accountType, accountUniqueID) + 
"'");) { 
 
  338                                 account = 
new Account(rs.getInt(
"account_id"), accountType,
 
  339                                                 rs.getString(
"account_unique_identifier"));
 
  341                 } 
catch (SQLException ex) {
 
  342                         throw new TskCoreException(
"Error getting account type id", ex);
 
  376                 if (sourceArtifact.getDataSourceObjectID() == null) {
 
  377                         throw new TskDataException(
"Source Artifact does not have a valid data source.");
 
  380                 if (relationshipType.isCreatableFrom(sourceArtifact) == 
false) {
 
  381                         throw new TskDataException(
"Can not make a " + relationshipType.getDisplayName()
 
  382                                         + 
" relationship from a" + sourceArtifact.getDisplayName());
 
  391                 List<Long> accountIDs = 
new ArrayList<>();
 
  393                 if (null != sender) {
 
  394                         accountIDs.add(sender.getAccount().getAccountID());
 
  395                         if (!sender.getDataSourceObjectID().equals(sourceArtifact.getDataSourceObjectID())) {
 
  396                                 throw new TskDataException(
"Sender and relationship are from different data sources :" 
  397                                                 + 
"Sender source ID" + sender.getDataSourceObjectID() + 
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
 
  402                         accountIDs.add(recipient.getAccount().getAccountID());
 
  403                         if (!recipient.getDataSourceObjectID().equals(sourceArtifact.getDataSourceObjectID())) {
 
  404                                 throw new TskDataException(
"Recipient and relationship are from different data sources :" 
  405                                                 + 
"Recipient source ID" + recipient.getDataSourceObjectID() + 
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
 
  410                 String query = 
"INTO account_relationships (account1_id, account2_id, relationship_source_obj_id, date_time, relationship_type, data_source_obj_id  ) " 
  411                                 + 
"VALUES (?,?,?,?,?,?)";
 
  414                                 query = 
"INSERT " + query + 
" ON CONFLICT DO NOTHING";
 
  417                                 query = 
"INSERT OR IGNORE " + query;
 
  420                                 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  426                         PreparedStatement preparedStatement = connection.getPreparedStatement(query, Statement.NO_GENERATED_KEYS);
 
  428                         for (
int i = 0; i < accountIDs.size(); i++) {
 
  429                                 for (
int j = i + 1; j < accountIDs.size(); j++) {
 
  430                                         long account1_id = accountIDs.get(i);
 
  431                                         long account2_id = accountIDs.get(j);
 
  433                                         preparedStatement.clearParameters();
 
  434                                         preparedStatement.setLong(1, account1_id);
 
  435                                         preparedStatement.setLong(2, account2_id);
 
  436                                         preparedStatement.setLong(3, sourceArtifact.getId());
 
  438                                                 preparedStatement.setLong(4, dateTime);
 
  440                                                 preparedStatement.setNull(4, java.sql.Types.BIGINT);
 
  442                                         preparedStatement.setInt(5, relationshipType.getTypeID());
 
  443                                         preparedStatement.setLong(6, sourceArtifact.getDataSourceObjectID());
 
  445                                         connection.executeUpdate(preparedStatement);
 
  449                 } 
catch (SQLException ex) {
 
  451                         throw new TskCoreException(
"Error adding accounts relationship", ex);
 
  471                 if (null == account) {
 
  472                         String query = 
" INTO accounts (account_type_id, account_unique_identifier) " 
  473                                         + 
"VALUES ( " + getAccountTypeId(accountType) + 
", '" 
  474                                         + normalizeAccountID(accountType, accountUniqueID) + 
"'" + 
")";
 
  477                                         query = 
"INSERT " + query + 
" ON CONFLICT DO NOTHING"; 
 
  480                                         query = 
"INSERT OR IGNORE " + query;
 
  483                                         throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  490                                 s = trans.getConnection().createStatement();
 
  495                                 account = 
getAccount(accountType, accountUniqueID);
 
  496                         } 
catch (SQLException ex) {
 
  498                                 throw new TskCoreException(
"Error adding an account", ex);
 
  528         private BlackboardArtifact getOrCreateAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, String moduleName, 
 
  529                         Content sourceFile, List<BlackboardAttribute> originalAttrs, Long ingestJobId) 
throws TskCoreException {
 
  530                 if (sourceFile == null) {
 
  531                         throw new TskCoreException(
"Source file not provided.");
 
  534                 BlackboardArtifact accountArtifact = getAccountFileInstanceArtifact(accountType, accountUniqueID, sourceFile);
 
  535                 if (accountArtifact == null) {
 
  536                         List<BlackboardAttribute> attributes = 
new ArrayList<>();
 
  537                         attributes.add(
new BlackboardAttribute(BlackboardAttribute.Type.TSK_ACCOUNT_TYPE, moduleName, accountType.getTypeName()));
 
  538                         attributes.add(
new BlackboardAttribute(BlackboardAttribute.Type.TSK_ID, moduleName, accountUniqueID));
 
  539                         if (originalAttrs != null) {
 
  540                                 attributes.addAll(originalAttrs);
 
  543                         accountArtifact = sourceFile.newDataArtifact(ACCOUNT_TYPE, attributes);
 
  547                         } 
catch (BlackboardException ex) {
 
  548                                 LOGGER.log(Level.SEVERE, String.format(
"Error posting new account artifact to the blackboard (object ID = %d)", accountArtifact.getId()), ex);
 
  551                 return accountArtifact;
 
  567         private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, Content sourceFile) 
throws TskCoreException {
 
  568                 BlackboardArtifact accountArtifact = null;
 
  570                 String queryStr = 
"SELECT artifacts.artifact_id AS artifact_id," 
  571                                 + 
" artifacts.obj_id AS obj_id," 
  572                                 + 
" artifacts.artifact_obj_id AS artifact_obj_id," 
  573                                 + 
" artifacts.data_source_obj_id AS data_source_obj_id," 
  574                                 + 
" artifacts.artifact_type_id AS artifact_type_id," 
  575                                 + 
" artifacts.review_status_id AS review_status_id," 
  576                                 + 
" tsk_data_artifacts.os_account_obj_id AS os_account_obj_id" 
  577                                 + 
" FROM blackboard_artifacts AS artifacts" 
  578                                 + 
"     JOIN blackboard_attributes AS attr_account_type" 
  579                                 + 
"             ON artifacts.artifact_id = attr_account_type.artifact_id" 
  580                                 + 
" JOIN blackboard_attributes AS attr_account_id" 
  581                                 + 
"             ON artifacts.artifact_id = attr_account_id.artifact_id" 
  582                                 + 
"             AND attr_account_id.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID()
 
  583                                 + 
"         AND attr_account_id.value_text = '" + accountUniqueID + 
"'" 
  584                                 + 
" LEFT JOIN tsk_data_artifacts ON tsk_data_artifacts.artifact_obj_id = artifacts.artifact_obj_id" 
  585                                 + 
" WHERE artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()
 
  586                                 + 
" AND attr_account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
 
  587                                 + 
" AND attr_account_type.value_text = '" + accountType.getTypeName() + 
"'" 
  588                                 + 
" AND artifacts.obj_id = " + sourceFile.getId(); 
 
  591                 try (CaseDbConnection connection = db.getConnection();
 
  592                                 Statement s = connection.createStatement();
 
  593                                 ResultSet rs = connection.executeQuery(s, queryStr);) { 
 
  597                                 accountArtifact = 
new DataArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"),
 
  598                                                 rs.getObject(
"data_source_obj_id") != null ? rs.getLong(
"data_source_obj_id") : null,
 
  599                                                 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
 
  600                                                 BlackboardArtifact.ReviewStatus.withID(rs.getInt(
"review_status_id")), rs.getLong(
"os_account_obj_id"), 
false);
 
  602                 } 
catch (SQLException ex) {
 
  603                         throw new TskCoreException(
"Error getting account", ex);
 
  608                 return accountArtifact;
 
  622                 if (this.typeNameToAccountTypeMap.containsKey(accountTypeName)) {
 
  623                         return this.typeNameToAccountTypeMap.get(accountTypeName);
 
  627                 try (CaseDbConnection connection = db.getConnection();
 
  628                                 Statement s = connection.createStatement();
 
  629                                 ResultSet rs = connection.executeQuery(s, 
"SELECT account_type_id, type_name, display_name FROM account_types WHERE type_name = '" + accountTypeName + 
"'");) { 
 
  632                                 accountType = 
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
 
  633                                 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
 
  634                                 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
 
  637                 } 
catch (SQLException ex) {
 
  638                         throw new TskCoreException(
"Error getting account type id", ex);
 
  661                 Set<String> applicableInnerQueryFilters = 
new HashSet<String>(Arrays.asList(
 
  666                 String relationshipFilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
 
  668                 String relationshipLimitSQL = getMostRecentFilterLimitSQL(filter);
 
  670                 String relTblfilterQuery
 
  672                                 + 
"FROM account_relationships as relationships" 
  673                                 + (relationshipFilterSQL.isEmpty() ? 
"" : 
" WHERE " + relationshipFilterSQL)
 
  674                                 + (relationshipLimitSQL.isEmpty() ? 
"" : relationshipLimitSQL);
 
  676                 String uniqueAccountQueryTemplate
 
  677                                 = 
" SELECT %1$1s as account_id," 
  678                                 + 
" data_source_obj_id" 
  679                                 + 
" FROM ( " + relTblfilterQuery + 
")AS %2$s";
 
  681                 String relationshipTableFilterQuery1 = String.format(uniqueAccountQueryTemplate, 
"account1_id", 
"union_query_1");
 
  682                 String relationshipTableFilterQuery2 = String.format(uniqueAccountQueryTemplate, 
"account2_id", 
"union_query_2");
 
  685                 String uniqueAccountQuery
 
  686                                 = 
"SELECT DISTINCT account_id, data_source_obj_id" 
  687                                 + 
" FROM ( " + relationshipTableFilterQuery1 + 
" UNION " + relationshipTableFilterQuery2 + 
" ) AS inner_union" 
  688                                 + 
" GROUP BY account_id, data_source_obj_id";
 
  691                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  695                 String accountTypeFilterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  699                                 " accounts.account_id AS account_id," 
  700                                 + 
" accounts.account_unique_identifier AS account_unique_identifier," 
  702                                 + 
" account_types.type_name AS type_name," 
  704                                 + 
" data_source_info.device_id AS device_id" 
  705                                 + 
" FROM ( " + uniqueAccountQuery + 
" ) AS account_device_instances" 
  706                                 + 
" JOIN accounts AS accounts" 
  707                                 + 
"             ON accounts.account_id = account_device_instances.account_id" 
  708                                 + 
" JOIN account_types AS account_types" 
  709                                 + 
"             ON accounts.account_type_id = account_types.account_type_id" 
  710                                 + 
" JOIN data_source_info AS data_source_info" 
  711                                 + 
"             ON account_device_instances.data_source_obj_id = data_source_info.obj_id" 
  712                                 + (accountTypeFilterSQL.isEmpty() ? 
"" : 
" WHERE " + accountTypeFilterSQL);
 
  716                                 queryStr = 
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
 
  719                                 queryStr = 
"SELECT " + queryStr + 
" GROUP BY accounts.account_id, data_source_info.device_id";
 
  722                                 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  726                 try (CaseDbConnection connection = db.getConnection();
 
  727                                 Statement s = connection.createStatement();
 
  728                                 ResultSet rs = connection.executeQuery(s, queryStr);) { 
 
  729                         ArrayList<AccountDeviceInstance> accountDeviceInstances = 
new ArrayList<AccountDeviceInstance>();
 
  731                                 long account_id = rs.getLong(
"account_id");
 
  732                                 String deviceID = rs.getString(
"device_id");
 
  733                                 final String type_name = rs.getString(
"type_name");
 
  734                                 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
 
  736                                 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
 
  737                                 Account account = 
new Account(account_id, accountType, account_unique_identifier);
 
  741                         return accountDeviceInstances;
 
  742                 } 
catch (SQLException ex) {
 
  743                         throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
 
  770                 Set<Long> accountIDs = 
new HashSet<Long>();
 
  771                 Set<String> accountDeviceIDs = 
new HashSet<String>();
 
  773                         accountIDs.add(adi.getAccount().getAccountID());
 
  774                         accountDeviceIDs.add(
"'" + adi.getDeviceId() + 
"'");
 
  777                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  783                 String accountIDsCSL = CommManagerSqlStringUtils.buildCSVString(accountIDs);
 
  784                 String accountDeviceIDsCSL = CommManagerSqlStringUtils.buildCSVString(accountDeviceIDs);
 
  785                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  787                 final String queryString
 
  788                                 = 
" SELECT  count(DISTINCT relationships.relationship_source_obj_id) AS count,"  
  789                                 + 
"             data_source_info.device_id AS device_id," 
  791                                 + 
"             accounts1.account_id AS account1_id," 
  792                                 + 
"             accounts1.account_unique_identifier AS account1_unique_identifier," 
  793                                 + 
"             account_types1.type_name AS type_name1," 
  794                                 + 
"             account_types1.display_name AS display_name1," 
  796                                 + 
"             accounts2.account_id AS account2_id," 
  797                                 + 
"             accounts2.account_unique_identifier AS account2_unique_identifier," 
  798                                 + 
"             account_types2.type_name AS type_name2," 
  799                                 + 
"             account_types2.display_name AS display_name2" 
  800                                 + 
" FROM account_relationships AS relationships" 
  801                                 + 
"     JOIN data_source_info AS data_source_info" 
  802                                 + 
"             ON relationships.data_source_obj_id = data_source_info.obj_id " 
  804                                 + 
"     JOIN accounts AS accounts1       " 
  805                                 + 
"             ON accounts1.account_id = relationships.account1_id" 
  806                                 + 
"     JOIN account_types AS account_types1" 
  807                                 + 
"             ON accounts1.account_type_id = account_types1.account_type_id" 
  809                                 + 
"     JOIN accounts AS accounts2       " 
  810                                 + 
"             ON accounts2.account_id = relationships.account2_id" 
  811                                 + 
"     JOIN account_types AS account_types2" 
  812                                 + 
"             ON accounts2.account_type_id = account_types2.account_type_id" 
  813                                 + 
" WHERE (( relationships.account1_id IN (" + accountIDsCSL + 
")) " 
  814                                 + 
"             AND ( relationships.account2_id IN ( " + accountIDsCSL + 
" ))" 
  815                                 + 
"             AND ( data_source_info.device_id IN (" + accountDeviceIDsCSL + 
"))) " 
  816                                 + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL)
 
  817                                 + 
"  GROUP BY data_source_info.device_id, " 
  818                                 + 
"             accounts1.account_id, " 
  819                                 + 
"             account_types1.type_name, " 
  820                                 + 
"             account_types1.display_name, " 
  821                                 + 
"             accounts2.account_id, " 
  822                                 + 
"             account_types2.type_name, " 
  823                                 + 
"             account_types2.display_name";
 
  825                 Map<AccountPair, Long> results = 
new HashMap<AccountPair, Long>();
 
  828                 try (CaseDbConnection connection = db.getConnection();
 
  829                                 Statement s = connection.createStatement();
 
  830                                 ResultSet rs = connection.executeQuery(s, queryString);) { 
 
  836                                                 rs.getString(
"account1_unique_identifier")),
 
  837                                                 rs.getString(
"device_id"));
 
  842                                                 rs.getString(
"account2_unique_identifier")),
 
  843                                                 rs.getString(
"device_id"));
 
  846                                 long count = rs.getLong(
"count");
 
  849                                 Long oldCount = results.get(relationshipKey);
 
  850                                 if (oldCount != null) {
 
  853                                 results.put(relationshipKey, count);
 
  856                 } 
catch (SQLException ex) {
 
  857                         throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
 
  880                 long account_id = accountDeviceInstance.getAccount().
getAccountID();
 
  883                 String datasourceObjIdsCSV = CommManagerSqlStringUtils.buildCSVString(
 
  884                                 db.getDataSourceObjIds(accountDeviceInstance.getDeviceId()));
 
  887                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  891                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  893                 String innerQuery = 
" account_relationships AS relationships";
 
  894                 String limitStr = getMostRecentFilterLimitSQL(filter);
 
  896                 if (!limitStr.isEmpty()) {
 
  897                         innerQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
  901                                 = 
"SELECT count(DISTINCT relationships.relationship_source_obj_id) as count " 
  902                                 + 
"     FROM" + innerQuery
 
  903                                 + 
" WHERE relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV + 
" )" 
  904                                 + 
" AND ( relationships.account1_id = " + account_id
 
  905                                 + 
"      OR  relationships.account2_id = " + account_id + 
" )" 
  906                                 + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL);
 
  909                 try (CaseDbConnection connection = db.getConnection();
 
  910                                 Statement s = connection.createStatement();
 
  911                                 ResultSet rs = connection.executeQuery(s, queryStr);) { 
 
  913                         return (rs.getLong(
"count"));
 
  914                 } 
catch (SQLException ex) {
 
  915                         throw new TskCoreException(
"Error getting relationships count for account device instance. " + ex.getMessage(), ex);
 
  939                 if (accountDeviceInstanceList.isEmpty()) {
 
  940                         LOGGER.log(Level.WARNING, 
"Empty accountDeviceInstanceList passed to getRelationshipSources");
 
  941                         return Collections.emptySet();
 
  946                 Map<Long, Set<Long>> accountIdToDatasourceObjIdMap = 
new HashMap<>();
 
  948                         long accountID = accountDeviceInstance.getAccount().
getAccountID();
 
  949                         List<Long> dataSourceObjIds = db.getDataSourceObjIds(accountDeviceInstance.getDeviceId());
 
  951                         if (accountIdToDatasourceObjIdMap.containsKey(accountID)) {
 
  952                                 accountIdToDatasourceObjIdMap.get(accountID).addAll(dataSourceObjIds);
 
  954                                 accountIdToDatasourceObjIdMap.put(accountID, 
new HashSet<>(dataSourceObjIds));
 
  959                 List<String> adiSQLClauses = 
new ArrayList<>();
 
  960                 for (Map.Entry<Long, Set<Long>> entry : accountIdToDatasourceObjIdMap.entrySet()) {
 
  961                         final Long accountID = entry.getKey();
 
  962                         String datasourceObjIdsCSV = CommManagerSqlStringUtils.buildCSVString(entry.getValue());
 
  966                                         + (!datasourceObjIdsCSV.isEmpty() ? 
"( relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV + 
" ) ) AND" : 
"")
 
  967                                         + 
" ( relationships.account1_id = " + accountID
 
  968                                         + 
" OR relationships.account2_id = " + accountID + 
" ) )" 
  971                 String adiSQLClause = CommManagerSqlStringUtils.joinAsStrings(adiSQLClauses, 
" OR ");
 
  973                 if(adiSQLClause.isEmpty()) {
 
  974                         LOGGER.log(Level.SEVERE, 
"There set of AccountDeviceInstances had no valid data source ids.");
 
  975                         return Collections.emptySet();
 
  979                 Set<String> applicableFilters = 
new HashSet<>(Arrays.asList(
 
  985                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  988                 String limitQuery = 
" account_relationships AS relationships";
 
  992                 String limitStr = getMostRecentFilterLimitSQL(filter);
 
  993                 if (!limitStr.isEmpty()) {
 
  994                         limitQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
  998                                 = 
"SELECT DISTINCT artifacts.artifact_id AS artifact_id," 
  999                                 + 
" artifacts.obj_id AS obj_id," 
 1000                                 + 
" artifacts.artifact_obj_id AS artifact_obj_id," 
 1001                                 + 
" artifacts.data_source_obj_id AS data_source_obj_id, " 
 1002                                 + 
" artifacts.artifact_type_id AS artifact_type_id, " 
 1003                                 + 
" artifacts.review_status_id AS review_status_id," 
 1004                                 + 
" tsk_data_artifacts.os_account_obj_id as os_account_obj_id" 
 1005                                 + 
" FROM blackboard_artifacts as artifacts" 
 1006                                 + 
" JOIN " + limitQuery
 
 1007                                 + 
"     ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id" 
 1008                                 + 
" LEFT JOIN tsk_data_artifacts ON artifacts.artifact_obj_id = tsk_data_artifacts.artifact_obj_id" 
 1010                                 + 
" WHERE (" + adiSQLClause + 
" )" 
 1012                                 + (filterSQL.isEmpty() ? 
"" : 
" AND (" + filterSQL + 
" )");
 
 1015                 try (CaseDbConnection connection = db.getConnection();
 
 1016                                 Statement s = connection.createStatement();
 
 1017                                 ResultSet rs = connection.executeQuery(s, queryStr);) { 
 
 1018                         Set<Content> relationshipSources = 
new HashSet<>();
 
 1019                         relationshipSources.addAll(getDataArtifactsFromResult(rs));
 
 1020                         return relationshipSources;
 
 1021                 } 
catch (SQLException ex) {
 
 1022                         throw new TskCoreException(
"Error getting relationships for account. " + ex.getMessage(), ex);
 
 1044                 final List<Long> dataSourceObjIds
 
 1045                                 = getSleuthkitCase().getDataSourceObjIds(accountDeviceInstance.getDeviceId());
 
 1048                 Set<String> applicableInnerQueryFilters = 
new HashSet<String>(Arrays.asList(
 
 1054                 String innerQueryfilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
 
 1056                 String innerQueryTemplate
 
 1057                                 = 
" SELECT %1$1s as account_id," 
 1058                                 + 
"               data_source_obj_id" 
 1059                                 + 
" FROM account_relationships as relationships" 
 1060                                 + 
" WHERE %2$1s = " + accountDeviceInstance.getAccount().getAccountID() + 
"" 
 1061                                 + 
" AND data_source_obj_id IN (" + CommManagerSqlStringUtils.buildCSVString(dataSourceObjIds) + 
")" 
 1062                                 + (innerQueryfilterSQL.isEmpty() ? 
"" : 
" AND " + innerQueryfilterSQL);
 
 1064                 String innerQuery1 = String.format(innerQueryTemplate, 
"account1_id", 
"account2_id");
 
 1065                 String innerQuery2 = String.format(innerQueryTemplate, 
"account2_id", 
"account1_id");
 
 1068                 String combinedInnerQuery
 
 1069                                 = 
"SELECT account_id, data_source_obj_id " 
 1070                                 + 
" FROM ( " + innerQuery1 + 
" UNION " + innerQuery2 + 
" ) AS  inner_union" 
 1071                                 + 
" GROUP BY account_id, data_source_obj_id";
 
 1074                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
 1078                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
 1082                                 " accounts.account_id AS account_id," 
 1083                                 + 
" accounts.account_unique_identifier AS account_unique_identifier," 
 1085                                 + 
" account_types.type_name AS type_name," 
 1087                                 + 
" data_source_info.device_id AS device_id" 
 1088                                 + 
" FROM ( " + combinedInnerQuery + 
" ) AS account_device_instances" 
 1089                                 + 
" JOIN accounts AS accounts" 
 1090                                 + 
"             ON accounts.account_id = account_device_instances.account_id" 
 1091                                 + 
" JOIN account_types AS account_types" 
 1092                                 + 
"             ON accounts.account_type_id = account_types.account_type_id" 
 1093                                 + 
" JOIN data_source_info AS data_source_info" 
 1094                                 + 
"             ON account_device_instances.data_source_obj_id = data_source_info.obj_id" 
 1095                                 + (filterSQL.isEmpty() ? 
"" : 
" WHERE " + filterSQL);
 
 1099                                 queryStr = 
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
 
 1102                                 queryStr = 
"SELECT " + queryStr + 
" GROUP BY accounts.account_id, data_source_info.device_id";
 
 1105                                 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
 1109                 try (CaseDbConnection connection = db.getConnection();
 
 1110                                 Statement s = connection.createStatement();
 
 1111                                 ResultSet rs = connection.executeQuery(s, queryStr);) {
 
 1112                         ArrayList<AccountDeviceInstance> accountDeviceInstances = 
new ArrayList<AccountDeviceInstance>();
 
 1114                                 long account_id = rs.getLong(
"account_id");
 
 1115                                 String deviceID = rs.getString(
"device_id");
 
 1116                                 final String type_name = rs.getString(
"type_name");
 
 1117                                 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
 
 1119                                 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
 
 1120                                 Account account = 
new Account(account_id, accountType, account_unique_identifier);
 
 1124                         return accountDeviceInstances;
 
 1125                 } 
catch (SQLException ex) {
 
 1126                         throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
 
 1151                 Set<String> applicableFilters = 
new HashSet<>(Arrays.asList(
 
 1157                 String limitQuery = 
" account_relationships AS relationships";
 
 1158                 String limitStr = getMostRecentFilterLimitSQL(filter);
 
 1159                 if (!limitStr.isEmpty()) {
 
 1160                         limitQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
 1163                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
 1164                 final String queryString = 
"SELECT artifacts.artifact_id AS artifact_id," 
 1165                                 + 
"             artifacts.obj_id AS obj_id," 
 1166                                 + 
"             artifacts.artifact_obj_id AS artifact_obj_id," 
 1167                                 + 
"             artifacts.data_source_obj_id AS data_source_obj_id," 
 1168                                 + 
"             artifacts.artifact_type_id AS artifact_type_id," 
 1169                                 + 
"             artifacts.review_status_id AS review_status_id," 
 1170                                 + 
"     tsk_data_artifacts.os_account_obj_id AS os_account_obj_id" 
 1171                                 + 
" FROM blackboard_artifacts AS artifacts" 
 1172                                 + 
"     JOIN " + limitQuery
 
 1173                                 + 
"             ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id" 
 1174                                 + 
" LEFT JOIN tsk_data_artifacts ON artifacts.artifact_obj_id = tsk_data_artifacts.artifact_obj_id" 
 1175                                 + 
" WHERE (( relationships.account1_id = " + account1.getAccount().getAccountID()
 
 1176                                 + 
" AND relationships.account2_id  = " + account2.getAccount().getAccountID()
 
 1177                                 + 
" ) OR (        relationships.account2_id = " + account1.getAccount().getAccountID()
 
 1178                                 + 
" AND relationships.account1_id =" + account2.getAccount().getAccountID() + 
" ))" 
 1179                                 + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL);
 
 1182                 try (CaseDbConnection connection = db.getConnection();
 
 1183                                 Statement s = connection.createStatement();
 
 1184                                 ResultSet rs = connection.executeQuery(s, queryString);) {
 
 1186                         ArrayList<Content> artifacts = 
new ArrayList<>();
 
 1187                         artifacts.addAll(getDataArtifactsFromResult(rs));
 
 1189                 } 
catch (SQLException ex) {
 
 1190                         throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
 
 1207                 List<AccountFileInstance> accountFileInstanceList = 
new ArrayList<>();
 
 1208                 @SuppressWarnings(
"deprecation")
 
 1211                 if (artifactList != null && !artifactList.isEmpty()) {
 
 1217                 if (!accountFileInstanceList.isEmpty()) {
 
 1218                         return accountFileInstanceList;
 
 1234                 String query = 
"SELECT DISTINCT accounts.account_type_id, type_name, display_name FROM accounts JOIN account_types ON accounts.account_type_id = account_types.account_type_id";
 
 1235                 List<
Account.
Type> inUseAccounts = 
new ArrayList<>();
 
 1238                 try (CaseDbConnection connection = db.getConnection();
 
 1239                                 Statement s = connection.createStatement();
 
 1240                                 ResultSet rs = connection.executeQuery(s, query);) {
 
 1243                                 String accountTypeName = rs.getString(
"type_name");
 
 1244                                 accountType = this.typeNameToAccountTypeMap.get(accountTypeName);
 
 1246                                 if (accountType == null) {
 
 1247                                         accountType = 
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
 
 1248                                         this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
 
 1251                                 inUseAccounts.add(accountType);
 
 1253                         return inUseAccounts;
 
 1254                 } 
catch (SQLException ex) {
 
 1255                         throw new TskCoreException(
"Error getting account type id", ex);
 
 1271                 if (artifact == null) {
 
 1272                         throw new IllegalArgumentException(
"null arugment passed to getAccountsRelatedToArtifact");
 
 1275                 List<Account> accountList = 
new ArrayList<>();
 
 1277                 try (CaseDbConnection connection = db.getConnection()) {
 
 1283                                 String query = String.format(
"SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1285                                                 + 
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1287                                                 + 
" JOIN account_relationships ON account1_id = account_id" 
 1288                                                 + 
" WHERE relationship_source_obj_id = %d" 
 1290                                                 + 
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1292                                                 + 
" JOIN account_relationships ON account2_id = account_id" 
 1293                                                 + 
" WHERE relationship_source_obj_id = %d) AS unionOfRelationships", artifact.getId(), artifact.getId());
 
 1294                                 try (Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(query)) {
 
 1297                                                 int accountTypeId = rs.getInt(
"account_type_id");
 
 1298                                                 for (Map.Entry<
Account.
Type, Integer> entry : accountTypeToTypeIdMap.entrySet()) {
 
 1299                                                         if (entry.getValue() == accountTypeId) {
 
 1300                                                                 accountType = entry.getKey();
 
 1305                                                 accountList.add(
new Account(rs.getInt(
"account_id"), accountType, rs.getString(
"account_unique_identifier")));
 
 1307                                 } 
catch (SQLException ex) {
 
 1308                                         throw new TskCoreException(
"Unable to get account list for give artifact " + artifact.getId(), ex);
 
 1327                 if (accountTypeToTypeIdMap.containsKey(accountType)) {
 
 1328                         return accountTypeToTypeIdMap.get(accountType);
 
 1345         private String normalizeAccountID(Account.Type accountType, String accountUniqueID) 
throws InvalidAccountIDException {
 
 1347                 if (accountUniqueID == null || accountUniqueID.isEmpty()) {
 
 1348                         throw new InvalidAccountIDException(
"Account id is null or empty.");
 
 1351                 String normalizedAccountID;
 
 1352                 if (accountType.equals(Account.Type.PHONE)) {
 
 1353                         normalizedAccountID = CommunicationsUtils.normalizePhoneNum(accountUniqueID);
 
 1354                 } 
else if (accountType.equals(Account.Type.EMAIL)) {
 
 1355                         normalizedAccountID = CommunicationsUtils.normalizeEmailAddress(accountUniqueID);
 
 1357                         normalizedAccountID = accountUniqueID.toLowerCase().trim();
 
 1360                 return normalizedAccountID;
 
 1375         private String getCommunicationsFilterSQL(CommunicationsFilter commFilter, Set<String> applicableFilters) {
 
 1376                 if (null == commFilter || commFilter.getAndFilters().isEmpty()) {
 
 1381                 StringBuilder sqlSB = 
new StringBuilder();
 
 1382                 boolean first = 
true;
 
 1383                 for (CommunicationsFilter.SubFilter subFilter : commFilter.getAndFilters()) {
 
 1386                         if (applicableFilters.contains(subFilter.getClass().getName())) {
 
 1387                                 String subfilterSQL = subFilter.getSQL(
this);
 
 1388                                 if (!subfilterSQL.isEmpty()) {
 
 1392                                                 sqlSB.append(
" AND ");
 
 1395                                         sqlSB.append(subfilterSQL);
 
 1401                 if (!sqlSB.toString().isEmpty()) {
 
 1402                         sqlStr = 
"( " + sqlSB.toString() + 
" )";
 
 1415         private String getMostRecentFilterLimitSQL(CommunicationsFilter filter) {
 
 1416                 String limitStr = 
"";
 
 1418                 if (filter != null && !filter.getAndFilters().isEmpty()) {
 
 1420                         for (CommunicationsFilter.SubFilter subFilter : filter.getAndFilters()) {
 
 1421                                 if (subFilter.getClass().getName().equals(CommunicationsFilter.MostRecentFilter.class.getName())) {
 
 1422                                         limitStr = subFilter.getSQL(
this);
 
 1442         private List<BlackboardArtifact> getDataArtifactsFromResult(ResultSet resultSet) 
throws SQLException, TskCoreException {
 
 1443                 List<BlackboardArtifact> artifacts = 
new ArrayList<>();
 
 1444                 while (resultSet.next()) {
 
 1446                         artifacts.add(
new DataArtifact(db, resultSet.getLong(
"artifact_id"),
 
 1447                                         resultSet.getLong(
"obj_id"), resultSet.getLong(
"artifact_obj_id"),
 
 1448                                         resultSet.getObject(
"data_source_obj_id") != null ? resultSet.getLong(
"data_source_obj_id") : null,
 
 1449                                         bbartType.getTypeID(),
 
 1450                                         bbartType.getTypeName(), bbartType.getDisplayName(),
 
 1451                                         BlackboardArtifact.ReviewStatus.withID(resultSet.getInt(
"review_status_id")),
 
 1452                                         resultSet.getLong(
"os_account_obj_id"), 
false));
 
Set< Content > getRelationshipSources(Set< AccountDeviceInstance > accountDeviceInstanceList, CommunicationsFilter filter)
 
void postArtifact(BlackboardArtifact artifact, String moduleName)
 
CaseDbTransaction beginTransaction()
 
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
 
Blackboard getBlackboard()
 
List< AccountDeviceInstance > getRelatedAccountDeviceInstances(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter)
 
org.sleuthkit.datamodel.Account.Type getAccountType(String accountTypeName)
 
AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile)
 
org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeName, String displayName)
 
List< Account > getAccountsRelatedToArtifact(BlackboardArtifact artifact)
 
String getTypeSpecificID()
 
Map< AccountPair, Long > getRelationshipCountsPairwise(Set< AccountDeviceInstance > accounts, CommunicationsFilter filter)
 
void releaseSingleUserCaseReadLock()
 
List< Account.Type > getAccountTypesInUse()
 
static final List< Account.Type > PREDEFINED_ACCOUNT_TYPES
 
BlackboardArtifact.Type getArtifactType(String artTypeName)
 
void acquireSingleUserCaseWriteLock()
 
void releaseSingleUserCaseWriteLock()
 
List< Content > getRelationshipSources(AccountDeviceInstance account1, AccountDeviceInstance account2, CommunicationsFilter filter)
 
long getRelationshipSourcesCount(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter)
 
AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile, List< BlackboardAttribute > attributes, Long ingestJobId)
 
void acquireSingleUserCaseReadLock()
 
List< AccountDeviceInstance > getAccountDeviceInstancesWithRelationships(CommunicationsFilter filter)
 
void addRelationships(AccountFileInstance sender, List< AccountFileInstance > recipients, BlackboardArtifact sourceArtifact, org.sleuthkit.datamodel.Relationship.Type relationshipType, long dateTime)
 
Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID)
 
List< AccountFileInstance > getAccountFileInstances(Account account)