diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java b/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java index ffdb6cf861..f75618b59b 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.coreutils; import java.io.File; import java.io.IOException; import java.sql.Connection; -import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; @@ -288,15 +287,94 @@ public final class AppSQLiteDB { } /** - * Returns connection meta data. - * - * @return DatabaseMetaData - * @throws SQLException + * Checks if a column exists in a table. + * + * @param tableName name of the table + * @param columnName column name to check + * + * @return true if the column exists, false otherwise + * @throws TskCoreException */ - public DatabaseMetaData getConnectionMetadata() throws SQLException { - return connection.getMetaData(); + public boolean columnExists(String tableName, String columnName) throws TskCoreException { + + boolean columnExists = false; + Statement colExistsStatement = null; + ResultSet resultSet = null; + try { + colExistsStatement = connection.createStatement(); + String tableInfoQuery = "PRAGMA table_info(%s)"; //NON-NLS + resultSet = colExistsStatement.executeQuery(String.format(tableInfoQuery, tableName)); + while (resultSet.next()) { + if (resultSet.getString("name").equalsIgnoreCase(columnName)) { + columnExists = true; + break; + } + } + } catch (SQLException ex) { + throw new TskCoreException("Error checking if column " + columnName + "exists ", ex); + } finally { + if (resultSet != null) { + try { + resultSet.close(); + } catch (SQLException ex2) { + logger.log(Level.WARNING, "Failed to close resultset after checking column", ex2); + } + } + if (colExistsStatement != null) { + try { + colExistsStatement.close(); + } catch (SQLException ex2) { + logger.log(Level.SEVERE, "Error closing Statement", ex2); //NON-NLS + } + } + } + return columnExists; } + /** + * Checks if a table exists in the case database. + * + * @param tableName name of the table to check + * + * @return true if the table exists, false otherwise + * @throws TskCoreException + */ + public boolean tableExists(String tableName) throws TskCoreException { + + boolean tableExists = false; + Statement tableExistsStatement = null; + ResultSet resultSet = null; + try { + + tableExistsStatement = connection.createStatement(); + resultSet = tableExistsStatement.executeQuery("SELECT name FROM sqlite_master WHERE type='table'"); //NON-NLS + while (resultSet.next()) { + if (resultSet.getString("name").equalsIgnoreCase(tableName)) { //NON-NLS + tableExists = true; + break; + } + } + } catch (SQLException ex) { + throw new TskCoreException("Error checking if table " + tableName + "exists ", ex); + } finally { + if (resultSet != null) { + try { + resultSet.close(); + } catch (SQLException ex2) { + logger.log(Level.WARNING, "Failed to close resultset after checking table", ex2); + } + } + if (tableExistsStatement != null) { + try { + tableExistsStatement.close(); + } catch (SQLException ex2) { + logger.log(Level.SEVERE, "Error closing Statement", ex2); //NON-NLS + } + } + } + return tableExists; + } + /** * Searches for a meta file associated with the give SQLite database. If * found, it copies this file into the temp directory of the current case. diff --git a/InternalPythonModules/android/calllog.py b/InternalPythonModules/android/calllog.py index 6f89d703ab..71c5f112ad 100644 --- a/InternalPythonModules/android/calllog.py +++ b/InternalPythonModules/android/calllog.py @@ -92,39 +92,41 @@ class CallLogAnalyzer(general.AndroidComponentAnalyzer): for tableName in CallLogAnalyzer._tableNames: try: - resultSet = callLogDb.runQuery("SELECT number, date, duration, type, name FROM " + tableName + " ORDER BY date DESC;") - self._logger.log(Level.INFO, "Reading call log from table {0} in db {1}", [tableName, callLogDb.getDBFile().getName()]) - if resultSet is not None: - while resultSet.next(): - direction = "" - callerId = None - calleeId = None - - timeStamp = resultSet.getLong("date") / 1000 - - number = resultSet.getString("number") - duration = resultSet.getLong("duration") # duration of call is in seconds - name = resultSet.getString("name") # name of person dialed or called. None if unregistered - - calltype = resultSet.getInt("type") - if calltype == 1 or calltype == 3: - direction = CommunicationDirection.INCOMING - callerId = number - elif calltype == 2 or calltype == 5: - direction = CommunicationDirection.OUTGOING - calleeId = number - else: - direction = CommunicationDirection.UNKNOWN + tableFound = callLogDb.tableExists(tableName) + if tableFound: + resultSet = callLogDb.runQuery("SELECT number, date, duration, type, name FROM " + tableName + " ORDER BY date DESC;") + self._logger.log(Level.INFO, "Reading call log from table {0} in db {1}", [tableName, callLogDb.getDBFile().getName()]) + if resultSet is not None: + while resultSet.next(): + direction = "" + callerId = None + calleeId = None + timeStamp = resultSet.getLong("date") / 1000 + + number = resultSet.getString("number") + duration = resultSet.getLong("duration") # duration of call is in seconds + name = resultSet.getString("name") # name of person dialed or called. None if unregistered - ## add a call log - if callerId is not None or calleeId is not None: - callLogArtifact = callLogDbHelper.addCalllog( direction, - callerId, - calleeId, - timeStamp, ## start time - timeStamp + duration * 1000, ## end time - CallMediaType.AUDIO) + calltype = resultSet.getInt("type") + if calltype == 1 or calltype == 3: + direction = CommunicationDirection.INCOMING + callerId = number + elif calltype == 2 or calltype == 5: + direction = CommunicationDirection.OUTGOING + calleeId = number + else: + direction = CommunicationDirection.UNKNOWN + + + ## add a call log + if callerId is not None or calleeId is not None: + callLogArtifact = callLogDbHelper.addCalllog( direction, + callerId, + calleeId, + timeStamp, ## start time + timeStamp + duration * 1000, ## end time + CallMediaType.AUDIO) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for Android messages.", ex) diff --git a/InternalPythonModules/android/contact.py b/InternalPythonModules/android/contact.py index 745440b6da..8144890134 100644 --- a/InternalPythonModules/android/contact.py +++ b/InternalPythonModules/android/contact.py @@ -102,13 +102,7 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer): # get display_name, mimetype(email or phone number) and data1 (phonenumber or email address depending on mimetype) # sorted by name, so phonenumber/email would be consecutive for a person if they exist. # check if contacts.name_raw_contact_id exists. Modify the query accordingly. - columnFound = False - metadata = contactDb.getConnectionMetadata() - columnListResultSet = metadata.getColumns(None, None, "contacts", None) - while columnListResultSet.next(): - if columnListResultSet.getString("COLUMN_NAME") == "name_raw_contact_id": - columnFound = True - break + columnFound = contactDb.columnExists("contacts", "name_raw_contact_id") if columnFound: resultSet = contactDb.runQuery( "SELECT mimetype, data1, name_raw_contact.display_name AS display_name \n"