Compare commits
1 Commits
test/ai-co
...
fix/verify
| Author | SHA1 | Date | |
|---|---|---|---|
|
1aaa382d5e
|
@@ -211,9 +211,13 @@ _first_pass(FILE* fp, const char* basename,
|
||||
|
||||
if (pl->stanza_id && pl->stanza_id[0] != '\0') {
|
||||
if (g_hash_table_contains(seen_stanza_ids, pl->stanza_id)) {
|
||||
*issues = g_slist_prepend(*issues,
|
||||
_issue_new(INTEGRITY_WARNING, basename, lineno,
|
||||
g_strdup_printf("Duplicate stanza-id \"%s\"", pl->stanza_id)));
|
||||
// Older clients (Pidgin, Adium, even early Profanity)
|
||||
// sometimes reuse client-generated stanza-ids across
|
||||
// distinct messages, so a collision is not a real
|
||||
// integrity defect — log it for diagnostics but don't
|
||||
// surface it through /history verify.
|
||||
log_debug("flatfile verify: duplicate stanza-id \"%s\" at %s:%d",
|
||||
pl->stanza_id, basename, lineno);
|
||||
} else {
|
||||
g_hash_table_insert(seen_stanza_ids, g_strdup(pl->stanza_id), GINT_TO_POINTER(lineno));
|
||||
}
|
||||
@@ -302,7 +306,13 @@ _verify_contact_dir(const char* cdir_path, GSList** issues)
|
||||
return;
|
||||
}
|
||||
|
||||
const char* basename = "history.log";
|
||||
// Reconstruct the contact JID from the directory name so issue reports
|
||||
// identify which contact the problem belongs to (every contact has its
|
||||
// own history.log, so the bare filename is ambiguous).
|
||||
auto_gchar gchar* dir_name = g_path_get_basename(cdir_path);
|
||||
auto_gcharv gchar** parts = g_strsplit(dir_name, "_at_", -1);
|
||||
auto_gchar gchar* contact_jid = g_strjoinv("@", parts);
|
||||
auto_gchar gchar* basename = g_strdup_printf("%s/history.log", contact_jid);
|
||||
|
||||
_check_permissions(filepath, basename, issues);
|
||||
|
||||
|
||||
@@ -466,23 +466,36 @@ _sqlite_verify_integrity(const gchar* const contact_barejid)
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
// Check timestamp ordering for a specific contact or all
|
||||
// Check timestamp ordering, restricted to consecutive rows belonging
|
||||
// to the same conversation pair so adjacency does not span unrelated
|
||||
// contacts. Adjacent rows by id from different conversations are
|
||||
// legitimately out-of-order and should not be reported.
|
||||
const Jid* myjid = connection_get_jid();
|
||||
if (myjid && myjid->barejid) {
|
||||
auto_sqlite char* query = NULL;
|
||||
if (contact_barejid) {
|
||||
query = sqlite3_mprintf(
|
||||
"SELECT A.`id`, A.`timestamp`, B.`id`, B.`timestamp` FROM `ChatLogs` A "
|
||||
"JOIN `ChatLogs` B ON B.`id` = A.`id` + 1 "
|
||||
"SELECT A.`id`, A.`timestamp`, A.`from_jid`, A.`to_jid`, B.`id`, B.`timestamp` "
|
||||
"FROM `ChatLogs` A "
|
||||
"JOIN `ChatLogs` B ON B.`from_jid` = A.`from_jid` AND B.`to_jid` = A.`to_jid` "
|
||||
" AND B.`id` > A.`id` "
|
||||
"WHERE A.`timestamp` > B.`timestamp` "
|
||||
"AND ((A.`from_jid` = %Q AND A.`to_jid` = %Q) OR (A.`from_jid` = %Q AND A.`to_jid` = %Q)) "
|
||||
"AND NOT EXISTS (SELECT 1 FROM `ChatLogs` C "
|
||||
" WHERE C.`from_jid` = A.`from_jid` AND C.`to_jid` = A.`to_jid` "
|
||||
" AND C.`id` > A.`id` AND C.`id` < B.`id`) "
|
||||
"LIMIT 50",
|
||||
contact_barejid, myjid->barejid, myjid->barejid, contact_barejid);
|
||||
} else {
|
||||
query = sqlite3_mprintf(
|
||||
"SELECT A.`id`, A.`timestamp`, B.`id`, B.`timestamp` FROM `ChatLogs` A "
|
||||
"JOIN `ChatLogs` B ON B.`id` = A.`id` + 1 "
|
||||
"SELECT A.`id`, A.`timestamp`, A.`from_jid`, A.`to_jid`, B.`id`, B.`timestamp` "
|
||||
"FROM `ChatLogs` A "
|
||||
"JOIN `ChatLogs` B ON B.`from_jid` = A.`from_jid` AND B.`to_jid` = A.`to_jid` "
|
||||
" AND B.`id` > A.`id` "
|
||||
"WHERE A.`timestamp` > B.`timestamp` "
|
||||
"AND NOT EXISTS (SELECT 1 FROM `ChatLogs` C "
|
||||
" WHERE C.`from_jid` = A.`from_jid` AND C.`to_jid` = A.`to_jid` "
|
||||
" AND C.`id` > A.`id` AND C.`id` < B.`id`) "
|
||||
"LIMIT 50");
|
||||
}
|
||||
|
||||
@@ -490,15 +503,19 @@ _sqlite_verify_integrity(const gchar* const contact_barejid)
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
int id_a = sqlite3_column_int(stmt, 0);
|
||||
const char* ts_a = (const char*)sqlite3_column_text(stmt, 1);
|
||||
int id_b = sqlite3_column_int(stmt, 2);
|
||||
const char* ts_b = (const char*)sqlite3_column_text(stmt, 3);
|
||||
const char* from_a = (const char*)sqlite3_column_text(stmt, 2);
|
||||
const char* to_a = (const char*)sqlite3_column_text(stmt, 3);
|
||||
int id_b = sqlite3_column_int(stmt, 4);
|
||||
const char* ts_b = (const char*)sqlite3_column_text(stmt, 5);
|
||||
|
||||
integrity_issue_t* issue = g_malloc0(sizeof(integrity_issue_t));
|
||||
issue->level = INTEGRITY_WARNING;
|
||||
issue->file = g_strdup("chatlog.db");
|
||||
issue->file = g_strdup_printf("%s↔%s/chatlog.db",
|
||||
from_a ? from_a : "?", to_a ? to_a : "?");
|
||||
issue->line = id_a;
|
||||
issue->message = g_strdup_printf("Timestamp out of order: row %d (%s) > row %d (%s)",
|
||||
id_a, ts_a ? ts_a : "NULL", id_b, ts_b ? ts_b : "NULL");
|
||||
id_a, ts_a ? ts_a : "NULL",
|
||||
id_b, ts_b ? ts_b : "NULL");
|
||||
issues = g_slist_append(issues, issue);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -506,7 +523,7 @@ _sqlite_verify_integrity(const gchar* const contact_barejid)
|
||||
|
||||
// Check broken LMC references
|
||||
auto_sqlite char* lmc_query = sqlite3_mprintf(
|
||||
"SELECT A.`id`, A.`replaces_db_id` FROM `ChatLogs` A "
|
||||
"SELECT A.`id`, A.`replaces_db_id`, A.`from_jid`, A.`to_jid` FROM `ChatLogs` A "
|
||||
"WHERE A.`replaces_db_id` IS NOT NULL "
|
||||
"AND NOT EXISTS (SELECT 1 FROM `ChatLogs` B WHERE B.`id` = A.`replaces_db_id`) "
|
||||
"LIMIT 50");
|
||||
@@ -515,10 +532,13 @@ _sqlite_verify_integrity(const gchar* const contact_barejid)
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
int id = sqlite3_column_int(stmt, 0);
|
||||
int replaces_id = sqlite3_column_int(stmt, 1);
|
||||
const char* from = (const char*)sqlite3_column_text(stmt, 2);
|
||||
const char* to = (const char*)sqlite3_column_text(stmt, 3);
|
||||
|
||||
integrity_issue_t* issue = g_malloc0(sizeof(integrity_issue_t));
|
||||
issue->level = INTEGRITY_ERROR;
|
||||
issue->file = g_strdup("chatlog.db");
|
||||
issue->file = g_strdup_printf("%s↔%s/chatlog.db",
|
||||
from ? from : "?", to ? to : "?");
|
||||
issue->line = id;
|
||||
issue->message = g_strdup_printf("Broken LMC reference: row %d references non-existent row %d",
|
||||
id, replaces_id);
|
||||
|
||||
Reference in New Issue
Block a user