From 1a54b57798686a9c8d5eb199b08b0b01145dd21d Mon Sep 17 00:00:00 2001 From: baraql Date: Wed, 11 Jan 2023 21:11:29 -0800 Subject: [PATCH 1/3] Read each affected row, extract text from attributedBody --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ iMessageAnalyzer/.DS_Store | Bin 6148 -> 6148 bytes iMessageAnalyzer/Assets.xcassets/.DS_Store | Bin 6148 -> 6148 bytes iMessageAnalyzer/StartupWindowController.m | 97 ++++++++++++++++++ import sqlite3.py | 2 + 5 files changed, 107 insertions(+) create mode 100644 iMessageAnalyzer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 import sqlite3.py diff --git a/iMessageAnalyzer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iMessageAnalyzer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/iMessageAnalyzer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/iMessageAnalyzer/.DS_Store b/iMessageAnalyzer/.DS_Store index ad65093b6167943ada5ce7c43d3f829b7c526579..e98cc22b7ee80cfc4d0e3858d96a171bd616b523 100644 GIT binary patch delta 264 zcmZoMXffE3!Xl8Alb^)Ez`)TU@Kl^-(-FtX1uSaV1eGQqVJU@6Or87;qFRlmw7r2Rv$}hkc d;ZljP8(pO=s?`M<$W|L{EIiD(nVsV=KLBufM1cSR delta 203 zcmZoMXffE3!orhMT9VAbaAnu0S_X#6b}TA^ zDywh~3xhL5K0^^hYEHUgaB_Zb0RtE$2mmR#TyDM#%npGYeP9Jha&Y@G Date: Thu, 12 Jan 2023 14:15:41 -0800 Subject: [PATCH 2/3] Fixed empty messages! --- iMessageAnalyzer/DatabaseManager.m | 39 +++- iMessageAnalyzer/StartupWindowController.m | 236 +++++++++++++-------- 2 files changed, 183 insertions(+), 92 deletions(-) diff --git a/iMessageAnalyzer/DatabaseManager.m b/iMessageAnalyzer/DatabaseManager.m index 3a2f5f2..00e30f3 100644 --- a/iMessageAnalyzer/DatabaseManager.m +++ b/iMessageAnalyzer/DatabaseManager.m @@ -365,7 +365,7 @@ - (NSMutableArray*) getAllMessagesForPerson:(Person *)person "CASE WHEN LENGTH(date) >= 18 " "THEN (date / 1000000000) " "ELSE date END AS adjusted_date, " - "date_read, is_from_me, cache_has_attachments, handle_id " + "date_read, is_from_me, cache_has_attachments, handle_id, attributedBody " "FROM message AS messageT " "INNER JOIN chat_message_join AS chatMessageT " "ON chatMessageT.chat_id IN (%@) " @@ -386,6 +386,43 @@ - (NSMutableArray*) getAllMessagesForPerson:(Person *)person NSString *text = @""; if(sqlite3_column_text(statement, 2) != NULL) { text = [NSString stringWithUTF8String: (const char*) sqlite3_column_text(statement, 2)]; + } else { + const void *blob = sqlite3_column_blob(statement, 10); + int blob_size = sqlite3_column_bytes(statement, 10); + + NSData *data = [NSData dataWithBytes:blob length:blob_size]; + + const char *bytes = [data bytes]; + char hexBuffer[2 * [data length] + 1]; // a buffer 2 times the size of data + 1 null character + int len = 0; + for (int i = 0; i < [data length]; i++) { + len += sprintf(hexBuffer + len, "%02x", bytes[i] & 0xff); + } + NSString* hexString = [NSString stringWithUTF8String:hexBuffer]; + NSRange range = [hexString rangeOfString:@"4e53537472696e67"]; + if (range.location != NSNotFound) { + hexString = [hexString substringFromIndex:range.location + range.length]; + hexString = [hexString substringFromIndex:12]; + } + range = [hexString rangeOfString:@"8684"]; + if (range.location != NSNotFound) { + hexString = [hexString substringToIndex:range.location]; + } + // hexString = [hexString stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSMutableData *newData= [[NSMutableData alloc] init]; + unsigned char whole_byte; + char byte_chars[3] = {'\0','\0','\0'}; + int i; + for (i=0; i < [hexString length]/2; i++) { + byte_chars[0] = [hexString characterAtIndex:i*2]; + byte_chars[1] = [hexString characterAtIndex:i*2+1]; + whole_byte = strtol(byte_chars, NULL, 16); + [newData appendBytes:&whole_byte length:1]; + } + NSString *result = [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]; + if (result) { + text = result; + } } const unsigned char *isIMessage = sqlite3_column_text(statement, 3); diff --git a/iMessageAnalyzer/StartupWindowController.m b/iMessageAnalyzer/StartupWindowController.m index 5707753..9bfe315 100644 --- a/iMessageAnalyzer/StartupWindowController.m +++ b/iMessageAnalyzer/StartupWindowController.m @@ -26,7 +26,7 @@ @implementation StartupWindowController * * Constructor * -*****************************************************************/ + *****************************************************************/ # pragma mark - Constructor @@ -103,7 +103,7 @@ - (void) checkForLatestVersion latestVersion = version; } } - + //If there's a later version, prompt for update if([latestVersionNumber isGreaterThan:myVersion] && latestVersion) { @@ -141,7 +141,7 @@ - (void) checkForLatestVersion * * StartupViewController Delegate * -*****************************************************************/ + *****************************************************************/ # pragma mark - StartupViewController Delegate @@ -184,7 +184,7 @@ - (void) didWishToExit * * Auxillary methods * -*****************************************************************/ + *****************************************************************/ # pragma mark - Auxillary methods @@ -250,7 +250,7 @@ - (void) iPhoneDataSource if(![fileManager fileExistsAtPath:iPhoneBackup]) { iPhoneBackup = [NSString stringWithFormat:@"%@/%@", filePath, fileName]; } - + if([fileManager fileExistsAtPath:iPhoneBackup]) { NSError *error; @@ -314,101 +314,155 @@ - (void) specificFileDataSource } //----------------- // Open the database - sqlite3 *db; - sqlite3_stmt *stmt; - int rc; - - NSString *databasePath = self.backupLocation; - rc = sqlite3_open([databasePath UTF8String], &db); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - // Prepare the SELECT statement - const char *sql = "SELECT ROWID, attributedBody FROM message WHERE text IS NULL AND attributedBody != '' ORDER BY date DESC LIMIT 10"; - rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - // Bind the parameter to the statement - rc = sqlite3_bind_text(stmt, 1, "some value", -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - // Step through the result set - while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { - // Extract the field of type blob - - int rowid = sqlite3_column_int(stmt, 0); - NSLog(@"%d", rowid); - - const void *blob = sqlite3_column_blob(stmt, 1); - int blob_size = sqlite3_column_bytes(stmt, 1); - - NSLog(@"%s", (char *) blob); + /* +// while (true) { + sqlite3 *db; + sqlite3_stmt *stmt; + int rc; - // Convert the blob data to an NSDictionary - NSData *data = [NSData dataWithBytes:blob length:blob_size]; + NSString *databasePath = self.backupLocation; + rc = sqlite3_open([databasePath UTF8String], &db); + if (rc != SQLITE_OK) { + // Error handling goes here + } - const char *bytes = [data bytes]; - char hexBuffer[2 * [data length] + 1]; // a buffer 2 times the size of data + 1 null character - int len = 0; - for (int i = 0; i < [data length]; i++) { - len += sprintf(hexBuffer + len, "%02x", bytes[i] & 0xff); + // Prepare the SELECT statement + const char *sql = "SELECT ROWID, attributedBody FROM message WHERE text IS NULL AND attributedBody != '' ORDER BY date DESC"; + rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + if (rc != SQLITE_OK) { + // Error handling goes here } - NSString* hexString = [NSString stringWithUTF8String:hexBuffer]; - NSRange range = [hexString rangeOfString:@"4e53537472696e67"]; - if (range.location != NSNotFound) { - hexString = [hexString substringFromIndex:range.location + range.length]; - hexString = [hexString substringFromIndex:12]; + + // Bind the parameter to the statement + rc = sqlite3_bind_text(stmt, 1, "some value", -1, SQLITE_STATIC); + if (rc != SQLITE_OK) { + // Error handling goes here } - range = [hexString rangeOfString:@"8684"]; - if (range.location != NSNotFound) { - hexString = [hexString substringToIndex:range.location]; + + NSMutableDictionary *toUpdate = [[NSMutableDictionary alloc] init]; + + // Step through the result set + while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + // Extract the field of type blob + + int rowid = sqlite3_column_int(stmt, 0); + NSLog(@"%d", rowid); + + const void *blob = sqlite3_column_blob(stmt, 1); + int blob_size = sqlite3_column_bytes(stmt, 1); + + NSLog(@"%s", (char *) blob); + + NSData *data = [NSData dataWithBytes:blob length:blob_size]; + + const char *bytes = [data bytes]; + char hexBuffer[2 * [data length] + 1]; // a buffer 2 times the size of data + 1 null character + int len = 0; + for (int i = 0; i < [data length]; i++) { + len += sprintf(hexBuffer + len, "%02x", bytes[i] & 0xff); + } + NSString* hexString = [NSString stringWithUTF8String:hexBuffer]; + NSRange range = [hexString rangeOfString:@"4e53537472696e67"]; + if (range.location != NSNotFound) { + hexString = [hexString substringFromIndex:range.location + range.length]; + hexString = [hexString substringFromIndex:12]; + } + range = [hexString rangeOfString:@"8684"]; + if (range.location != NSNotFound) { + hexString = [hexString substringToIndex:range.location]; + } + NSLog(@"%@", hexString); + // hexString = [hexString stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSMutableData *newData= [[NSMutableData alloc] init]; + unsigned char whole_byte; + char byte_chars[3] = {'\0','\0','\0'}; + int i; + for (i=0; i < [hexString length]/2; i++) { + byte_chars[0] = [hexString characterAtIndex:i*2]; + byte_chars[1] = [hexString characterAtIndex:i*2+1]; + whole_byte = strtol(byte_chars, NULL, 16); + [newData appendBytes:&whole_byte length:1]; + } + NSString *result = [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]; + NSLog(@"%@", result); + + if (!result) { + continue; + } + + [toUpdate setObject:result forKey:[NSNumber numberWithInt:rowid]]; + + // Update the row's text field + // NSString *updateSQL = [NSString stringWithFormat:@"UPDATE tablename SET text = '%@' WHERE rowid = %d", result, rowid]; + // const char *update_stmt = [updateSQL UTF8String]; + /* + NSString *updateSQL = [NSString stringWithFormat:@"UPDATE message SET text = '%@' WHERE ROWID = %d", result, rowid]; + const char *updateSql = [updateSQL UTF8String]; + + // char *updateSql = "UPDATE message SET text = 'new_text' WHERE rowid = x"; + char *errMsg; + int updateResult = sqlite3_exec(db, updateSql, NULL, NULL, &errMsg); + if (updateResult != SQLITE_OK) { + NSLog(@"Error"); + // Handle the error + } + + + NSLog(@"----------------------"); } - NSLog(@"%@", hexString); -// hexString = [hexString stringByReplacingOccurrencesOfString:@" " withString:@""]; - NSMutableData *newData= [[NSMutableData alloc] init]; - unsigned char whole_byte; - char byte_chars[3] = {'\0','\0','\0'}; - int i; - for (i=0; i < [hexString length]/2; i++) { - byte_chars[0] = [hexString characterAtIndex:i*2]; - byte_chars[1] = [hexString characterAtIndex:i*2+1]; - whole_byte = strtol(byte_chars, NULL, 16); - [newData appendBytes:&whole_byte length:1]; + + // Finalize the statement + rc = sqlite3_finalize(stmt); + if (rc != SQLITE_OK) { + // Error handling goes here } - NSString *result = [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]; - NSLog(@"%@", result); - // Update the row's text field -// NSString *updateSQL = [NSString stringWithFormat:@"UPDATE tablename SET text = '%@' WHERE rowid = %d", result, rowid]; -// const char *update_stmt = [updateSQL UTF8String]; -// -// if (sqlite3_prepare_v2(db, update_stmt, -1, &updateStmt, NULL) == SQLITE_OK) { -// sqlite3_step(updateStmt); -// sqlite3_finalize(updateStmt); + + + for (id key in toUpdate) { + NSString *value = [toUpdate objectForKey:key]; + if (!value) { + continue; + } + value = [value stringByReplacingOccurrencesOfString:@"'" withString:@"''"]; + NSString *sql = [NSString stringWithFormat:@"UPDATE message SET text = '%@' WHERE rowid = %@", value, key]; + NSLog(@"%@", sql); + char *err_msg; + sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err_msg); + if (err_msg != nil) { + NSLog(@"SQL Error: %s", err_msg); + } + } + */ + // Close the database +// rc = sqlite3_close(db); +// if (rc != SQLITE_OK) { +// // Error handling goes here // } -// sqlite3_close(db); - - } + /* + sql = "SELECT text FROM message WHERE rowid = 384496"; + rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + if (rc != SQLITE_OK) { + // Error handling goes here + } - NSLog(@"----------------------"); - } - - // Finalize the statement - rc = sqlite3_finalize(stmt); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - // Close the database - rc = sqlite3_close(db); - if (rc != SQLITE_OK) { - // Error handling goes here - } + // Bind the parameter to the statement + rc = sqlite3_bind_text(stmt, 1, "some value", -1, SQLITE_STATIC); + if (rc != SQLITE_OK) { + // Error handling goes here + } + + // Step through the result set + while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + // Extract the field of type blob + + const unsigned char *text = sqlite3_column_text(stmt, 0); + NSLog(@"384496: %s", text); + } + */ +// } + + } } From cacc29b716495ac990f82ad63531bee0f2149b9a Mon Sep 17 00:00:00 2001 From: baraql Date: Thu, 12 Jan 2023 14:18:43 -0800 Subject: [PATCH 3/3] Reverted StartupWindowController --- iMessageAnalyzer/StartupWindowController.m | 161 +-------------------- 1 file changed, 5 insertions(+), 156 deletions(-) diff --git a/iMessageAnalyzer/StartupWindowController.m b/iMessageAnalyzer/StartupWindowController.m index 9bfe315..516cbb0 100644 --- a/iMessageAnalyzer/StartupWindowController.m +++ b/iMessageAnalyzer/StartupWindowController.m @@ -26,7 +26,7 @@ @implementation StartupWindowController * * Constructor * - *****************************************************************/ +*****************************************************************/ # pragma mark - Constructor @@ -103,7 +103,7 @@ - (void) checkForLatestVersion latestVersion = version; } } - + //If there's a later version, prompt for update if([latestVersionNumber isGreaterThan:myVersion] && latestVersion) { @@ -141,7 +141,7 @@ - (void) checkForLatestVersion * * StartupViewController Delegate * - *****************************************************************/ +*****************************************************************/ # pragma mark - StartupViewController Delegate @@ -184,7 +184,7 @@ - (void) didWishToExit * * Auxillary methods * - *****************************************************************/ +*****************************************************************/ # pragma mark - Auxillary methods @@ -250,7 +250,7 @@ - (void) iPhoneDataSource if(![fileManager fileExistsAtPath:iPhoneBackup]) { iPhoneBackup = [NSString stringWithFormat:@"%@/%@", filePath, fileName]; } - + if([fileManager fileExistsAtPath:iPhoneBackup]) { NSError *error; @@ -312,157 +312,6 @@ - (void) specificFileDataSource NSLog(@"Copied DB\nFROM: %@\nTO: %@\n", databaseFilePath, self.backupLocation); [self showMainWindow:self.backupLocation]; } - //----------------- - // Open the database - /* -// while (true) { - sqlite3 *db; - sqlite3_stmt *stmt; - int rc; - - NSString *databasePath = self.backupLocation; - rc = sqlite3_open([databasePath UTF8String], &db); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - // Prepare the SELECT statement - const char *sql = "SELECT ROWID, attributedBody FROM message WHERE text IS NULL AND attributedBody != '' ORDER BY date DESC"; - rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - // Bind the parameter to the statement - rc = sqlite3_bind_text(stmt, 1, "some value", -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - NSMutableDictionary *toUpdate = [[NSMutableDictionary alloc] init]; - - // Step through the result set - while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { - // Extract the field of type blob - - int rowid = sqlite3_column_int(stmt, 0); - NSLog(@"%d", rowid); - - const void *blob = sqlite3_column_blob(stmt, 1); - int blob_size = sqlite3_column_bytes(stmt, 1); - - NSLog(@"%s", (char *) blob); - - NSData *data = [NSData dataWithBytes:blob length:blob_size]; - - const char *bytes = [data bytes]; - char hexBuffer[2 * [data length] + 1]; // a buffer 2 times the size of data + 1 null character - int len = 0; - for (int i = 0; i < [data length]; i++) { - len += sprintf(hexBuffer + len, "%02x", bytes[i] & 0xff); - } - NSString* hexString = [NSString stringWithUTF8String:hexBuffer]; - NSRange range = [hexString rangeOfString:@"4e53537472696e67"]; - if (range.location != NSNotFound) { - hexString = [hexString substringFromIndex:range.location + range.length]; - hexString = [hexString substringFromIndex:12]; - } - range = [hexString rangeOfString:@"8684"]; - if (range.location != NSNotFound) { - hexString = [hexString substringToIndex:range.location]; - } - NSLog(@"%@", hexString); - // hexString = [hexString stringByReplacingOccurrencesOfString:@" " withString:@""]; - NSMutableData *newData= [[NSMutableData alloc] init]; - unsigned char whole_byte; - char byte_chars[3] = {'\0','\0','\0'}; - int i; - for (i=0; i < [hexString length]/2; i++) { - byte_chars[0] = [hexString characterAtIndex:i*2]; - byte_chars[1] = [hexString characterAtIndex:i*2+1]; - whole_byte = strtol(byte_chars, NULL, 16); - [newData appendBytes:&whole_byte length:1]; - } - NSString *result = [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]; - NSLog(@"%@", result); - - if (!result) { - continue; - } - - [toUpdate setObject:result forKey:[NSNumber numberWithInt:rowid]]; - - // Update the row's text field - // NSString *updateSQL = [NSString stringWithFormat:@"UPDATE tablename SET text = '%@' WHERE rowid = %d", result, rowid]; - // const char *update_stmt = [updateSQL UTF8String]; - /* - NSString *updateSQL = [NSString stringWithFormat:@"UPDATE message SET text = '%@' WHERE ROWID = %d", result, rowid]; - const char *updateSql = [updateSQL UTF8String]; - - // char *updateSql = "UPDATE message SET text = 'new_text' WHERE rowid = x"; - char *errMsg; - int updateResult = sqlite3_exec(db, updateSql, NULL, NULL, &errMsg); - if (updateResult != SQLITE_OK) { - NSLog(@"Error"); - // Handle the error - } - - - NSLog(@"----------------------"); - } - - // Finalize the statement - rc = sqlite3_finalize(stmt); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - - - for (id key in toUpdate) { - NSString *value = [toUpdate objectForKey:key]; - if (!value) { - continue; - } - value = [value stringByReplacingOccurrencesOfString:@"'" withString:@"''"]; - NSString *sql = [NSString stringWithFormat:@"UPDATE message SET text = '%@' WHERE rowid = %@", value, key]; - NSLog(@"%@", sql); - char *err_msg; - sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err_msg); - if (err_msg != nil) { - NSLog(@"SQL Error: %s", err_msg); - } - } - */ - // Close the database -// rc = sqlite3_close(db); -// if (rc != SQLITE_OK) { -// // Error handling goes here -// } - /* - sql = "SELECT text FROM message WHERE rowid = 384496"; - rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - // Bind the parameter to the statement - rc = sqlite3_bind_text(stmt, 1, "some value", -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - // Error handling goes here - } - - // Step through the result set - while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { - // Extract the field of type blob - - const unsigned char *text = sqlite3_column_text(stmt, 0); - NSLog(@"384496: %s", text); - } - */ -// } - - } }