19 package org.sleuthkit.datamodel;
 
   21 import java.sql.ResultSet;
 
   22 import java.sql.SQLException;
 
   23 import java.sql.Statement;
 
   24 import java.util.ArrayList;
 
   25 import java.util.Arrays;
 
   26 import java.util.Collection;
 
   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;
 
   51         private final Map<
Account.
Type, Integer> accountTypeToTypeIdMap
 
   52                         = 
new ConcurrentHashMap<>();
 
   53         private final Map<String, 
Account.
Type> typeNameToAccountTypeMap
 
   54                         = 
new ConcurrentHashMap<>();
 
   57         private static final Set<Integer> RELATIONSHIP_ARTIFACT_TYPE_IDS = 
new HashSet<Integer>(Arrays.asList(
 
   63         private static final String RELATIONSHIP_ARTIFACT_TYPE_IDS_CSV_STR = StringUtils.buildCSVString(RELATIONSHIP_ARTIFACT_TYPE_IDS);
 
   85                 CaseDbConnection connection = db.getConnection();
 
   87                 Statement statement = null;
 
   88                 ResultSet resultSet = null;
 
   91                         statement = connection.createStatement();
 
   93                         int count = readAccountTypes();
 
   98                                                 statement.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + type.getTypeName() + 
"', '" + type.getDisplayName() + 
"')"); 
 
   99                                         } 
catch (SQLException ex) {
 
  100                                                 resultSet = connection.executeQuery(statement, 
"SELECT COUNT(*) AS count FROM account_types WHERE type_name = '" + type.getTypeName() + 
"'"); 
 
  102                                                 if (resultSet.getLong(
"count") == 0) {
 
  108                                         ResultSet rs2 = connection.executeQuery(statement, 
"SELECT account_type_id FROM account_types WHERE type_name = '" + type.getTypeName() + 
"'"); 
 
  110                                         int typeID = rs2.getInt(
"account_type_id");
 
  114                                         this.accountTypeToTypeIdMap.put(accountType, typeID);
 
  115                                         this.typeNameToAccountTypeMap.put(type.getTypeName(), accountType);
 
  118                 } 
catch (SQLException ex) {
 
  119                         LOGGER.log(Level.SEVERE, 
"Failed to add row to account_types", ex);
 
  121                         closeResultSet(resultSet);
 
  122                         closeStatement(statement);
 
  137                 CaseDbConnection connection = db.getConnection();
 
  139                 Statement statement = null;
 
  140                 ResultSet resultSet = null;
 
  144                         statement = connection.createStatement();
 
  147                         resultSet = connection.executeQuery(statement, 
"SELECT COUNT(*) AS count FROM account_types"); 
 
  149                         if (resultSet.getLong(
"count") > 0) {
 
  152                                 resultSet = connection.executeQuery(statement, 
"SELECT * FROM account_types");
 
  153                                 while (resultSet.next()) {
 
  154                                         Account.
Type accountType = 
new Account.
Type(resultSet.getString(
"type_name"), resultSet.getString(
"display_name"));
 
  155                                         this.accountTypeToTypeIdMap.put(accountType, resultSet.getInt(
"account_type_id"));
 
  156                                         this.typeNameToAccountTypeMap.put(accountType.getTypeName(), accountType);
 
  158                                 count = this.typeNameToAccountTypeMap.size();
 
  161                 } 
catch (SQLException ex) {
 
  164                         closeResultSet(resultSet);
 
  165                         closeStatement(statement);
 
  199                 if (this.accountTypeToTypeIdMap.containsKey(accountType)) {
 
  203                 CaseDbConnection connection = db.getConnection();
 
  208                         connection.beginTransaction();
 
  209                         s = connection.createStatement();
 
  210                         rs = connection.executeQuery(s, 
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName + 
"'"); 
 
  214                                 s.execute(
"INSERT INTO account_types (type_name, display_name) VALUES ( '" + accountTypeName + 
"', '" + displayName + 
"')"); 
 
  217                                 rs = connection.executeQuery(s, 
"SELECT * FROM account_types WHERE type_name = '" + accountTypeName + 
"'"); 
 
  220                                 int typeID = rs.getInt(
"account_type_id");
 
  221                                 accountType = 
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
 
  223                                 this.accountTypeToTypeIdMap.put(accountType, typeID);
 
  224                                 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
 
  226                                 connection.commitTransaction();
 
  230                                 int typeID = rs.getInt(
"account_type_id");
 
  232                                 accountType = 
new Account.
Type(rs.getString(
"type_name"), rs.getString(
"display_name"));
 
  233                                 this.accountTypeToTypeIdMap.put(accountType, typeID);
 
  237                 } 
catch (SQLException ex) {
 
  238                         connection.rollbackTransaction();
 
  270                 Account account = getOrCreateAccount(accountType, normalizeAccountID(accountType, accountUniqueID));
 
  278                 BlackboardArtifact accountArtifact = getOrCreateAccountFileInstanceArtifact(accountType, normalizeAccountID(accountType, accountUniqueID), moduleName, sourceFile);
 
  305                 CaseDbConnection connection = db.getConnection();
 
  310                         s = connection.createStatement();
 
  311                         rs = connection.executeQuery(s, 
"SELECT * FROM accounts WHERE account_type_id = " + getAccountTypeId(accountType)
 
  312                                         + 
" AND account_unique_identifier = '" + normalizeAccountID(accountType, accountUniqueID) + 
"'"); 
 
  315                                 account = 
new Account(rs.getInt(
"account_id"), accountType,
 
  316                                                 rs.getString(
"account_unique_identifier"));
 
  318                 } 
catch (SQLException ex) {
 
  319                         throw new TskCoreException(
"Error getting account type id", ex);
 
  356                 if (relationshipType.isCreatableFrom(sourceArtifact) == 
false) {
 
  357                         throw new TskDataException(
"Can not make a " + relationshipType.getDisplayName()
 
  358                                         + 
" relationship from a" + sourceArtifact.getDisplayName());
 
  367                 List<Long> accountIDs = 
new ArrayList<Long>();
 
  369                 if (null != sender) {
 
  370                         accountIDs.add(sender.getAccount().getAccountID());
 
  371                         if (sender.getDataSourceObjectID() != sourceArtifact.getDataSourceObjectID()) {
 
  372                                 throw new TskDataException(
"Sender and relationship are from different data sources :" 
  373                                                 + 
"Sender source ID" + sender.getDataSourceObjectID() + 
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
 
  378                         accountIDs.add(recipient.getAccount().getAccountID());
 
  379                         if (recipient.getDataSourceObjectID() != sourceArtifact.getDataSourceObjectID()) {
 
  380                                 throw new TskDataException(
"Recipient and relationship are from different data sources :" 
  381                                                 + 
"Recipient source ID" + recipient.getDataSourceObjectID() + 
" != relationship source ID" + sourceArtifact.getDataSourceObjectID());
 
  385                 for (
int i = 0; i < accountIDs.size(); i++) {
 
  386                         for (
int j = i + 1; j < accountIDs.size(); j++) {
 
  388                                         addAccountsRelationship(accountIDs.get(i), accountIDs.get(j),
 
  389                                                         sourceArtifact, relationshipType, dateTime);
 
  390                                 } 
catch (TskCoreException ex) {
 
  392                                         LOGGER.log(Level.WARNING, 
"Error adding relationship", ex); 
 
  414                 if (null == account) {
 
  415                         String query = 
" INTO accounts (account_type_id, account_unique_identifier) " 
  416                                         + 
"VALUES ( " + getAccountTypeId(accountType) + 
", '" 
  417                                         + normalizeAccountID(accountType, accountUniqueID) + 
"'" + 
")";
 
  420                                         query = 
"INSERT " + query + 
" ON CONFLICT DO NOTHING"; 
 
  423                                         query = 
"INSERT OR IGNORE " + query;
 
  426                                         throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  429                         CaseDbConnection connection = db.getConnection();
 
  434                                 connection.beginTransaction();
 
  435                                 s = connection.createStatement();
 
  439                                 connection.commitTransaction();
 
  440                                 account = 
getAccount(accountType, accountUniqueID);
 
  441                         } 
catch (SQLException ex) {
 
  442                                 connection.rollbackTransaction();
 
  443                                 throw new TskCoreException(
"Error adding an account", ex);
 
  472         private BlackboardArtifact getOrCreateAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, String moduleName, Content sourceFile) 
throws TskCoreException {
 
  473                 BlackboardArtifact accountArtifact = getAccountFileInstanceArtifact(accountType, accountUniqueID, sourceFile);
 
  474                 if (accountArtifact == null) {
 
  475                         accountArtifact = db.
newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT, sourceFile.getId());
 
  476                         Collection<BlackboardAttribute> attributes = 
new ArrayList<>();
 
  477                         attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, moduleName, accountType.getTypeName()));
 
  478                         attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID, moduleName, accountUniqueID));
 
  482                         } 
catch (BlackboardException ex) {
 
  483                                 LOGGER.log(Level.SEVERE, String.format(
"Error posting new account artifact to the blackboard (object ID = %d)", accountArtifact.getId()), ex);
 
  486                 return accountArtifact;
 
  502         private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountType, String accountUniqueID, Content sourceFile) 
throws TskCoreException {
 
  503                 BlackboardArtifact accountArtifact = null;
 
  504                 CaseDbConnection connection = db.getConnection();
 
  510                         s = connection.createStatement();
 
  511                         String queryStr = 
"SELECT artifacts.artifact_id AS artifact_id," 
  512                                         + 
" artifacts.obj_id AS obj_id," 
  513                                         + 
" artifacts.artifact_obj_id AS artifact_obj_id," 
  514                                         + 
" artifacts.data_source_obj_id AS data_source_obj_id," 
  515                                         + 
" artifacts.artifact_type_id AS artifact_type_id," 
  516                                         + 
" artifacts.review_status_id AS review_status_id" 
  517                                         + 
" FROM blackboard_artifacts AS artifacts" 
  518                                         + 
"     JOIN blackboard_attributes AS attr_account_type" 
  519                                         + 
"             ON artifacts.artifact_id = attr_account_type.artifact_id" 
  520                                         + 
" JOIN blackboard_attributes AS attr_account_id" 
  521                                         + 
"             ON artifacts.artifact_id = attr_account_id.artifact_id" 
  522                                         + 
"             AND attr_account_id.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID()
 
  523                                         + 
"         AND attr_account_id.value_text = '" + accountUniqueID + 
"'" 
  524                                         + 
" WHERE artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()
 
  525                                         + 
" AND attr_account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
 
  526                                         + 
" AND attr_account_type.value_text = '" + accountType.getTypeName() + 
"'" 
  527                                         + 
" AND artifacts.obj_id = " + sourceFile.getId(); 
 
  529                         rs = connection.executeQuery(s, queryStr); 
 
  531                                 BlackboardArtifact.Type bbartType = db.
getArtifactType(rs.getInt(
"artifact_type_id"));
 
  533                                 accountArtifact = 
new BlackboardArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"), rs.getLong(
"data_source_obj_id"),
 
  534                                                 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
 
  535                                                 BlackboardArtifact.ReviewStatus.withID(rs.getInt(
"review_status_id")));
 
  537                 } 
catch (SQLException ex) {
 
  538                         throw new TskCoreException(
"Error getting account", ex);
 
  546                 return accountArtifact;
 
  560                 if (this.typeNameToAccountTypeMap.containsKey(accountTypeName)) {
 
  561                         return this.typeNameToAccountTypeMap.get(accountTypeName);
 
  564                 CaseDbConnection connection = db.getConnection();
 
  570                         s = connection.createStatement();
 
  571                         rs = connection.executeQuery(s, 
"SELECT account_type_id, type_name, display_name FROM account_types WHERE type_name = '" + accountTypeName + 
"'"); 
 
  574                                 accountType = 
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
 
  575                                 this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
 
  576                                 this.typeNameToAccountTypeMap.put(accountTypeName, accountType);
 
  579                 } 
catch (SQLException ex) {
 
  580                         throw new TskCoreException(
"Error getting account type id", ex);
 
  602         private void addAccountsRelationship(
long account1_id, 
long account2_id, 
BlackboardArtifact relationshipaArtifact, 
Relationship.
Type relationshipType, 
long dateTime) 
throws TskCoreException {
 
  603                 CaseDbConnection connection = db.getConnection();
 
  609                         String dateTimeValStr = (dateTime > 0) ? Long.toString(dateTime) : 
"NULL";
 
  611                         connection.beginTransaction();
 
  612                         s = connection.createStatement();
 
  613                         String query = 
"INTO account_relationships (account1_id, account2_id, relationship_source_obj_id, date_time, relationship_type, data_source_obj_id  ) " 
  614                                         + 
"VALUES ( " + account1_id + 
", " + account2_id + 
", " + relationshipaArtifact.getId() + 
", " + dateTimeValStr + 
", " + relationshipType.getTypeID() + 
", " + relationshipaArtifact.getDataSourceObjectID() + 
")";
 
  617                                         query = 
"INSERT " + query + 
" ON CONFLICT DO NOTHING";
 
  620                                         query = 
"INSERT OR IGNORE " + query;
 
  623                                         throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  626                         connection.commitTransaction();
 
  627                 } 
catch (SQLException ex) {
 
  628                         connection.rollbackTransaction();
 
  629                         throw new TskCoreException(
"Error adding accounts relationship", ex);
 
  653                 CaseDbConnection connection = db.getConnection();
 
  659                         s = connection.createStatement();
 
  662                         Set<String> applicableInnerQueryFilters = 
new HashSet<String>(Arrays.asList(
 
  667                         String relationshipFilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
 
  669                         String relationshipLimitSQL = getMostRecentFilterLimitSQL(filter);
 
  671                         String relTblfilterQuery
 
  673                                         + 
"FROM account_relationships as relationships" 
  674                                         + (relationshipFilterSQL.isEmpty() ? 
"" : 
" WHERE " + relationshipFilterSQL)
 
  675                                         + (relationshipLimitSQL.isEmpty() ? 
"" : relationshipLimitSQL);
 
  677                         String uniqueAccountQueryTemplate
 
  678                                         = 
" SELECT %1$1s as account_id," 
  679                                         + 
" data_source_obj_id" 
  680                                         + 
" FROM ( " + relTblfilterQuery + 
")AS %2$s";
 
  682                         String relationshipTableFilterQuery1 = String.format(uniqueAccountQueryTemplate, 
"account1_id", 
"union_query_1");
 
  683                         String relationshipTableFilterQuery2 = String.format(uniqueAccountQueryTemplate, 
"account2_id", 
"union_query_2");
 
  686                         String uniqueAccountQuery
 
  687                                         = 
"SELECT DISTINCT account_id, data_source_obj_id" 
  688                                         + 
" FROM ( " + relationshipTableFilterQuery1 + 
" UNION " + relationshipTableFilterQuery2 + 
" ) AS inner_union" 
  689                                         + 
" GROUP BY account_id, data_source_obj_id";
 
  692                         Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  696                         String accountTypeFilterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  700                                         " accounts.account_id AS account_id," 
  701                                         + 
" accounts.account_unique_identifier AS account_unique_identifier," 
  703                                         + 
" account_types.type_name AS type_name," 
  705                                         + 
" data_source_info.device_id AS device_id" 
  706                                         + 
" FROM ( " + uniqueAccountQuery + 
" ) AS account_device_instances" 
  707                                         + 
" JOIN accounts AS accounts" 
  708                                         + 
"             ON accounts.account_id = account_device_instances.account_id" 
  709                                         + 
" JOIN account_types AS account_types" 
  710                                         + 
"             ON accounts.account_type_id = account_types.account_type_id" 
  711                                         + 
" JOIN data_source_info AS data_source_info" 
  712                                         + 
"             ON account_device_instances.data_source_obj_id = data_source_info.obj_id" 
  713                                         + (accountTypeFilterSQL.isEmpty() ? 
"" : 
" WHERE " + accountTypeFilterSQL);
 
  717                                         queryStr = 
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
 
  720                                         queryStr = 
"SELECT " + queryStr + 
" GROUP BY accounts.account_id, data_source_info.device_id";
 
  723                                         throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
  726                         rs = connection.executeQuery(s, queryStr); 
 
  727                         ArrayList<AccountDeviceInstance> accountDeviceInstances = 
new ArrayList<AccountDeviceInstance>();
 
  729                                 long account_id = rs.getLong(
"account_id");
 
  730                                 String deviceID = rs.getString(
"device_id");
 
  731                                 final String type_name = rs.getString(
"type_name");
 
  732                                 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
 
  734                                 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
 
  735                                 Account account = 
new Account(account_id, accountType, account_unique_identifier);
 
  739                         return accountDeviceInstances;
 
  740                 } 
catch (SQLException ex) {
 
  741                         throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
 
  771                 Set<Long> accountIDs = 
new HashSet<Long>();
 
  772                 Set<String> accountDeviceIDs = 
new HashSet<String>();
 
  774                         accountIDs.add(adi.getAccount().getAccountID());
 
  775                         accountDeviceIDs.add(
"'" + adi.getDeviceId() + 
"'");
 
  778                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  784                 String accountIDsCSL = StringUtils.buildCSVString(accountIDs);
 
  785                 String accountDeviceIDsCSL = StringUtils.buildCSVString(accountDeviceIDs);
 
  786                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  788                 final String queryString
 
  789                                 = 
" SELECT  count(DISTINCT relationships.relationship_source_obj_id) AS count,"  
  790                                 + 
"             data_source_info.device_id AS device_id," 
  792                                 + 
"             accounts1.account_id AS account1_id," 
  793                                 + 
"             accounts1.account_unique_identifier AS account1_unique_identifier," 
  794                                 + 
"             account_types1.type_name AS type_name1," 
  795                                 + 
"             account_types1.display_name AS display_name1," 
  797                                 + 
"             accounts2.account_id AS account2_id," 
  798                                 + 
"             accounts2.account_unique_identifier AS account2_unique_identifier," 
  799                                 + 
"             account_types2.type_name AS type_name2," 
  800                                 + 
"             account_types2.display_name AS display_name2" 
  801                                 + 
" FROM account_relationships AS relationships" 
  802                                 + 
"     JOIN data_source_info AS data_source_info" 
  803                                 + 
"             ON relationships.data_source_obj_id = data_source_info.obj_id " 
  805                                 + 
"     JOIN accounts AS accounts1       " 
  806                                 + 
"             ON accounts1.account_id = relationships.account1_id" 
  807                                 + 
"     JOIN account_types AS account_types1" 
  808                                 + 
"             ON accounts1.account_type_id = account_types1.account_type_id" 
  810                                 + 
"     JOIN accounts AS accounts2       " 
  811                                 + 
"             ON accounts2.account_id = relationships.account2_id" 
  812                                 + 
"     JOIN account_types AS account_types2" 
  813                                 + 
"             ON accounts2.account_type_id = account_types2.account_type_id" 
  814                                 + 
" WHERE (( relationships.account1_id IN (" + accountIDsCSL + 
")) " 
  815                                 + 
"             AND ( relationships.account2_id IN ( " + accountIDsCSL + 
" ))" 
  816                                 + 
"             AND ( data_source_info.device_id IN (" + accountDeviceIDsCSL + 
"))) " 
  817                                 + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL)
 
  818                                 + 
"  GROUP BY data_source_info.device_id, " 
  819                                 + 
"             accounts1.account_id, " 
  820                                 + 
"             account_types1.type_name, " 
  821                                 + 
"             account_types1.display_name, " 
  822                                 + 
"             accounts2.account_id, " 
  823                                 + 
"             account_types2.type_name, " 
  824                                 + 
"             account_types2.display_name";
 
  825                 CaseDbConnection connection = db.getConnection();
 
  830                 Map<AccountPair, Long> results = 
new HashMap<AccountPair, Long>();
 
  833                         s = connection.createStatement();
 
  834                         rs = connection.executeQuery(s, queryString); 
 
  840                                                 rs.getString(
"account1_unique_identifier")),
 
  841                                                 rs.getString(
"device_id"));
 
  846                                                 rs.getString(
"account2_unique_identifier")),
 
  847                                                 rs.getString(
"device_id"));
 
  850                                 long count = rs.getLong(
"count");
 
  853                                 Long oldCount = results.get(relationshipKey);
 
  854                                 if (oldCount != null) {
 
  857                                 results.put(relationshipKey, count);
 
  860                 } 
catch (SQLException ex) {
 
  861                         throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
 
  887                 long account_id = accountDeviceInstance.getAccount().
getAccountID();
 
  890                 String datasourceObjIdsCSV = StringUtils.buildCSVString(
 
  891                                 db.getDataSourceObjIds(accountDeviceInstance.getDeviceId()));
 
  894                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  898                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  900                 CaseDbConnection connection = db.getConnection();
 
  906                         s = connection.createStatement();
 
  908                         String innerQuery = 
" account_relationships AS relationships";
 
  909                         String limitStr = getMostRecentFilterLimitSQL(filter);
 
  911                         if (!limitStr.isEmpty()) {
 
  912                                 innerQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
  916                                         = 
"SELECT count(DISTINCT relationships.relationship_source_obj_id) as count " 
  917                                         + 
"     FROM" + innerQuery
 
  918                                         + 
" WHERE relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV + 
" )" 
  919                                         + 
" AND ( relationships.account1_id = " + account_id
 
  920                                         + 
"      OR  relationships.account2_id = " + account_id + 
" )" 
  921                                         + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL);
 
  923                         rs = connection.executeQuery(s, queryStr); 
 
  925                         return (rs.getLong(
"count"));
 
  926                 } 
catch (SQLException ex) {
 
  927                         throw new TskCoreException(
"Error getting relationships count for account device instance. " + ex.getMessage(), ex);
 
  954                 if (accountDeviceInstanceList.isEmpty()) {
 
  956                         return Collections.emptySet();
 
  959                 Map<Long, Set<Long>> accountIdToDatasourceObjIdMap = 
new HashMap<Long, Set<Long>>();
 
  961                         long accountID = accountDeviceInstance.getAccount().
getAccountID();
 
  962                         List<Long> dataSourceObjIds = db.getDataSourceObjIds(accountDeviceInstance.getDeviceId());
 
  964                         if (accountIdToDatasourceObjIdMap.containsKey(accountID)) {
 
  965                                 accountIdToDatasourceObjIdMap.get(accountID).addAll(dataSourceObjIds);
 
  967                                 accountIdToDatasourceObjIdMap.put(accountID, 
new HashSet<Long>(dataSourceObjIds));
 
  971                 List<String> adiSQLClauses = 
new ArrayList<String>();
 
  972                 for (Map.Entry<Long, Set<Long>> entry : accountIdToDatasourceObjIdMap.entrySet()) {
 
  973                         final Long accountID = entry.getKey();
 
  974                         String datasourceObjIdsCSV = StringUtils.buildCSVString(entry.getValue());
 
  977                                         "( ( relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV + 
" ) )" 
  978                                         + 
" AND ( relationships.account1_id = " + accountID
 
  979                                         + 
" OR relationships.account2_id = " + accountID + 
" ) )" 
  982                 String adiSQLClause = StringUtils.joinAsStrings(adiSQLClauses, 
" OR ");
 
  985                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
  991                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
  993                 String limitQuery = 
" account_relationships AS relationships";
 
  994                 String limitStr = getMostRecentFilterLimitSQL(filter);
 
  995                 if (!limitStr.isEmpty()) {
 
  996                         limitQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
  999                 CaseDbConnection connection = db.getConnection();
 
 1002                 ResultSet rs = null;
 
 1005                         s = connection.createStatement();
 
 1007                                         = 
"SELECT DISTINCT artifacts.artifact_id AS artifact_id," 
 1008                                         + 
" artifacts.obj_id AS obj_id," 
 1009                                         + 
" artifacts.artifact_obj_id AS artifact_obj_id," 
 1010                                         + 
" artifacts.data_source_obj_id AS data_source_obj_id, " 
 1011                                         + 
" artifacts.artifact_type_id AS artifact_type_id, " 
 1012                                         + 
" artifacts.review_status_id AS review_status_id  " 
 1013                                         + 
" FROM blackboard_artifacts as artifacts" 
 1014                                         + 
" JOIN " + limitQuery
 
 1015                                         + 
"     ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id" 
 1017                                         + 
" WHERE (" + adiSQLClause + 
" )" 
 1019                                         + (filterSQL.isEmpty() ? 
"" : 
" AND (" + filterSQL + 
" )");
 
 1021                         rs = connection.executeQuery(s, queryStr); 
 
 1022                         Set<Content> relationshipSources = 
new HashSet<Content>();
 
 1026                                                 rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"),
 
 1027                                                 rs.getLong(
"data_source_obj_id"), bbartType.getTypeID(),
 
 1028                                                 bbartType.getTypeName(), bbartType.getDisplayName(),
 
 1032                         return relationshipSources;
 
 1033                 } 
catch (SQLException ex) {
 
 1034                         throw new TskCoreException(
"Error getting relationships for account. " + ex.getMessage(), ex);
 
 1059                 final List<Long> dataSourceObjIds
 
 1060                                 = getSleuthkitCase().getDataSourceObjIds(accountDeviceInstance.getDeviceId());
 
 1063                 Set<String> applicableInnerQueryFilters = 
new HashSet<String>(Arrays.asList(
 
 1069                 String innerQueryfilterSQL = getCommunicationsFilterSQL(filter, applicableInnerQueryFilters);
 
 1071                 String innerQueryTemplate
 
 1072                                 = 
" SELECT %1$1s as account_id," 
 1073                                 + 
"               data_source_obj_id" 
 1074                                 + 
" FROM account_relationships as relationships" 
 1075                                 + 
" WHERE %2$1s = " + accountDeviceInstance.getAccount().getAccountID() + 
"" 
 1076                                 + 
" AND data_source_obj_id IN (" + StringUtils.buildCSVString(dataSourceObjIds) + 
")" 
 1077                                 + (innerQueryfilterSQL.isEmpty() ? 
"" : 
" AND " + innerQueryfilterSQL);
 
 1079                 String innerQuery1 = String.format(innerQueryTemplate, 
"account1_id", 
"account2_id");
 
 1080                 String innerQuery2 = String.format(innerQueryTemplate, 
"account2_id", 
"account1_id");
 
 1083                 String combinedInnerQuery
 
 1084                                 = 
"SELECT account_id, data_source_obj_id " 
 1085                                 + 
" FROM ( " + innerQuery1 + 
" UNION " + innerQuery2 + 
" ) AS  inner_union" 
 1086                                 + 
" GROUP BY account_id, data_source_obj_id";
 
 1089                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
 1093                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
 1097                                 " accounts.account_id AS account_id," 
 1098                                 + 
" accounts.account_unique_identifier AS account_unique_identifier," 
 1100                                 + 
" account_types.type_name AS type_name," 
 1102                                 + 
" data_source_info.device_id AS device_id" 
 1103                                 + 
" FROM ( " + combinedInnerQuery + 
" ) AS account_device_instances" 
 1104                                 + 
" JOIN accounts AS accounts" 
 1105                                 + 
"             ON accounts.account_id = account_device_instances.account_id" 
 1106                                 + 
" JOIN account_types AS account_types" 
 1107                                 + 
"             ON accounts.account_type_id = account_types.account_type_id" 
 1108                                 + 
" JOIN data_source_info AS data_source_info" 
 1109                                 + 
"             ON account_device_instances.data_source_obj_id = data_source_info.obj_id" 
 1110                                 + (filterSQL.isEmpty() ? 
"" : 
" WHERE " + filterSQL);
 
 1114                                 queryStr = 
"SELECT DISTINCT ON ( accounts.account_id, data_source_info.device_id) " + queryStr;
 
 1117                                 queryStr = 
"SELECT " + queryStr + 
" GROUP BY accounts.account_id, data_source_info.device_id";
 
 1120                                 throw new TskCoreException(
"Unknown DB Type: " + db.
getDatabaseType().name());
 
 1123                 CaseDbConnection connection = db.getConnection();
 
 1126                 ResultSet rs = null;
 
 1129                         s = connection.createStatement();
 
 1131                         rs = connection.executeQuery(s, queryStr); 
 
 1132                         ArrayList<AccountDeviceInstance> accountDeviceInstances = 
new ArrayList<AccountDeviceInstance>();
 
 1134                                 long account_id = rs.getLong(
"account_id");
 
 1135                                 String deviceID = rs.getString(
"device_id");
 
 1136                                 final String type_name = rs.getString(
"type_name");
 
 1137                                 final String account_unique_identifier = rs.getString(
"account_unique_identifier");
 
 1139                                 Account.
Type accountType = typeNameToAccountTypeMap.get(type_name);
 
 1140                                 Account account = 
new Account(account_id, accountType, account_unique_identifier);
 
 1144                         return accountDeviceInstances;
 
 1145                 } 
catch (SQLException ex) {
 
 1146                         throw new TskCoreException(
"Error getting account device instances. " + ex.getMessage(), ex);
 
 1174                 Set<String> applicableFilters = 
new HashSet<String>(Arrays.asList(
 
 1180                 String limitQuery = 
" account_relationships AS relationships";
 
 1181                 String limitStr = getMostRecentFilterLimitSQL(filter);
 
 1182                 if (!limitStr.isEmpty()) {
 
 1183                         limitQuery = 
"(SELECT * FROM account_relationships as relationships " + limitStr + 
") as relationships";
 
 1186                 String filterSQL = getCommunicationsFilterSQL(filter, applicableFilters);
 
 1187                 final String queryString = 
"SELECT artifacts.artifact_id AS artifact_id," 
 1188                                 + 
"             artifacts.obj_id AS obj_id," 
 1189                                 + 
"             artifacts.artifact_obj_id AS artifact_obj_id," 
 1190                                 + 
"             artifacts.data_source_obj_id AS data_source_obj_id," 
 1191                                 + 
"             artifacts.artifact_type_id AS artifact_type_id," 
 1192                                 + 
"             artifacts.review_status_id AS review_status_id" 
 1193                                 + 
" FROM blackboard_artifacts AS artifacts" 
 1194                                 + 
"     JOIN " + limitQuery
 
 1195                                 + 
"             ON artifacts.artifact_obj_id = relationships.relationship_source_obj_id" 
 1196                                 + 
" WHERE (( relationships.account1_id = " + account1.getAccount().getAccountID()
 
 1197                                 + 
" AND relationships.account2_id  = " + account2.getAccount().getAccountID()
 
 1198                                 + 
" ) OR (        relationships.account2_id = " + account1.getAccount().getAccountID()
 
 1199                                 + 
" AND relationships.account1_id =" + account2.getAccount().getAccountID() + 
" ))" 
 1200                                 + (filterSQL.isEmpty() ? 
"" : 
" AND " + filterSQL);
 
 1201                 CaseDbConnection connection = db.getConnection();
 
 1204                 ResultSet rs = null;
 
 1206                         s = connection.createStatement();
 
 1207                         rs = connection.executeQuery(s, queryString); 
 
 1209                         ArrayList<Content> artifacts = 
new ArrayList<Content>();
 
 1212                                 artifacts.add(
new BlackboardArtifact(db, rs.getLong(
"artifact_id"), rs.getLong(
"obj_id"), rs.getLong(
"artifact_obj_id"), rs.getLong(
"data_source_obj_id"),
 
 1213                                                 bbartType.getTypeID(), bbartType.getTypeName(), bbartType.getDisplayName(),
 
 1218                 } 
catch (SQLException ex) {
 
 1219                         throw new TskCoreException(
"Error getting relationships between accounts. " + ex.getMessage(), ex);
 
 1239                 List<AccountFileInstance> accountFileInstanceList = 
new ArrayList<>();
 
 1243                 if (artifactList != null && !artifactList.isEmpty()) {
 
 1249                 if (!accountFileInstanceList.isEmpty()) {
 
 1250                         return accountFileInstanceList;
 
 1265                 CaseDbConnection connection = db.getConnection();
 
 1268                 ResultSet rs = null;
 
 1269                 List<
Account.
Type> inUseAccounts = 
new ArrayList<>();
 
 1272                         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";
 
 1273                         s = connection.createStatement();
 
 1274                         rs = connection.executeQuery(s, query); 
 
 1277                                 String accountTypeName = rs.getString(
"type_name");
 
 1278                                 accountType = this.typeNameToAccountTypeMap.get(accountTypeName);
 
 1280                                 if (accountType == null) {
 
 1281                                         accountType = 
new Account.
Type(accountTypeName, rs.getString(
"display_name"));
 
 1282                                         this.accountTypeToTypeIdMap.put(accountType, rs.getInt(
"account_type_id"));
 
 1285                                 inUseAccounts.add(accountType);
 
 1287                         return inUseAccounts;
 
 1288                 } 
catch (SQLException ex) {
 
 1289                         throw new TskCoreException(
"Error getting account type id", ex);
 
 1308                 if (artifact == null) {
 
 1309                         throw new IllegalArgumentException(
"null arugment passed to getAccountsRelatedToArtifact");
 
 1312                 List<Account> accountList = 
new ArrayList<>();
 
 1313                 try (CaseDbConnection connection = db.getConnection()) {
 
 1320                                 String query = String.format(
"SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1322                                                 + 
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1324                                                 + 
" JOIN account_relationships ON account1_id = account_id" 
 1325                                                 + 
" WHERE relationship_source_obj_id = %d" 
 1327                                                 + 
" SELECT DISTINCT (account_id), account_type_id, account_unique_identifier" 
 1329                                                 + 
" JOIN account_relationships ON account2_id = account_id" 
 1330                                                 + 
" WHERE relationship_source_obj_id = %d) AS unionOfRelationships", artifact.getId(), artifact.getId());
 
 1331                                 try (Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(query)) {
 
 1334                                                 int accountTypeId = rs.getInt(
"account_type_id");
 
 1335                                                 for (Map.Entry<
Account.
Type, Integer> entry : accountTypeToTypeIdMap.entrySet()) {
 
 1336                                                         if (entry.getValue() == accountTypeId) {
 
 1337                                                                 accountType = entry.getKey();
 
 1342                                                 accountList.add(
new Account(rs.getInt(
"account_id"), accountType, rs.getString(
"account_unique_identifier")));
 
 1344                                 } 
catch (SQLException ex) {
 
 1345                                         throw new TskCoreException(
"Unable to get account list for give artifact " + artifact.getId(), ex);
 
 1364                 if (accountTypeToTypeIdMap.containsKey(accountType)) {
 
 1365                         return accountTypeToTypeIdMap.get(accountType);
 
 1382         private String normalizeAccountID(Account.Type accountType, String accountUniqueID) 
throws InvalidAccountIDException {
 
 1384                 if (accountUniqueID == null || accountUniqueID.isEmpty()) {
 
 1385                         throw new InvalidAccountIDException(
"Account id is null or empty.");
 
 1388                 String normalizedAccountID;
 
 1389                 if (accountType.equals(Account.Type.PHONE)) {
 
 1390                         normalizedAccountID = CommunicationsUtils.normalizePhoneNum(accountUniqueID);
 
 1391                 } 
else if (accountType.equals(Account.Type.EMAIL)) {
 
 1392                         normalizedAccountID = CommunicationsUtils.normalizeEmailAddress(accountUniqueID);
 
 1394                         normalizedAccountID = accountUniqueID.toLowerCase().trim();
 
 1397                 return normalizedAccountID;
 
 1412         private String getCommunicationsFilterSQL(CommunicationsFilter commFilter, Set<String> applicableFilters) {
 
 1413                 if (null == commFilter || commFilter.getAndFilters().isEmpty()) {
 
 1418                 StringBuilder sqlSB = 
new StringBuilder();
 
 1419                 boolean first = 
true;
 
 1420                 for (CommunicationsFilter.SubFilter subFilter : commFilter.getAndFilters()) {
 
 1423                         if (applicableFilters.contains(subFilter.getClass().getName())) {
 
 1424                                 String subfilterSQL = subFilter.getSQL(
this);
 
 1425                                 if (!subfilterSQL.isEmpty()) {
 
 1429                                                 sqlSB.append(
" AND ");
 
 1432                                         sqlSB.append(subfilterSQL);
 
 1438                 if (!sqlSB.toString().isEmpty()) {
 
 1439                         sqlStr = 
"( " + sqlSB.toString() + 
" )";
 
 1452         private String getMostRecentFilterLimitSQL(CommunicationsFilter filter) {
 
 1453                 String limitStr = 
"";
 
 1455                 if (filter != null && !filter.getAndFilters().isEmpty()) {
 
 1457                         for (CommunicationsFilter.SubFilter subFilter : filter.getAndFilters()) {
 
 1458                                 if (subFilter.getClass().getName().equals(CommunicationsFilter.MostRecentFilter.class.getName())) {
 
 1459                                         limitStr = subFilter.getSQL(
this);
 
Set< Content > getRelationshipSources(Set< AccountDeviceInstance > accountDeviceInstanceList, CommunicationsFilter filter)
 
void postArtifact(BlackboardArtifact artifact, String moduleName)
 
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
 
Blackboard getBlackboard()
 
void addAttributes(Collection< BlackboardAttribute > attributes)
 
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()
 
BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id)
 
static final List< Account.Type > PREDEFINED_ACCOUNT_TYPES
 
void acquireSingleUserCaseWriteLock()
 
BlackboardArtifact.Type getArtifactType(String artTypeName)
 
void releaseSingleUserCaseWriteLock()
 
List< Content > getRelationshipSources(AccountDeviceInstance account1, AccountDeviceInstance account2, CommunicationsFilter filter)
 
long getRelationshipSourcesCount(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter)
 
void acquireSingleUserCaseReadLock()
 
List< AccountDeviceInstance > getAccountDeviceInstancesWithRelationships(CommunicationsFilter filter)
 
static ReviewStatus withID(int id)
 
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)