Merge branch 'master' into feat/ai

This commit is contained in:
2026-05-06 13:57:13 +00:00
50 changed files with 13810 additions and 793 deletions

View File

@@ -6687,6 +6687,13 @@ cmd_privacy(ProfWin* window, const char* const command, gchar** args)
} else if (g_strcmp0(arg, "redact") == 0) {
cons_show("Messages are going to be redacted.");
prefs_set_string(PREF_DBLOG, arg);
} else if (g_strcmp0(arg, "flatfile") == 0) {
auto_gchar gchar* ff_path = files_get_data_path(DIR_FLATLOG);
cons_show("Using flat-file backend for message logging. Takes effect on next connection.");
cons_show("Flatfile directory: %s", ff_path);
prefs_set_string(PREF_DBLOG, arg);
prefs_set_boolean(PREF_CHLOG, TRUE);
prefs_set_boolean(PREF_HISTORY, TRUE);
} else {
cons_bad_cmd_usage(command);
return TRUE;
@@ -6723,6 +6730,54 @@ cmd_logging(ProfWin* window, const char* const command, gchar** args)
return TRUE;
}
static void
_show_integrity_issues(GSList* issues)
{
int errors = 0, warnings = 0, infos = 0;
for (GSList* l = issues; l; l = l->next) {
integrity_issue_t* issue = l->data;
const char* level_str;
switch (issue->level) {
case INTEGRITY_ERROR:
level_str = "ERROR";
errors++;
break;
case INTEGRITY_WARNING:
level_str = "WARN";
warnings++;
break;
case INTEGRITY_INFO:
level_str = "INFO";
infos++;
break;
default:
level_str = "???";
break;
}
if (issue->line > 0) {
if (issue->level == INTEGRITY_ERROR) {
cons_show_error("[%s] %s:%d — %s", level_str, issue->file, issue->line, issue->message);
} else {
cons_show("[%s] %s:%d — %s", level_str, issue->file, issue->line, issue->message);
}
} else {
if (issue->level == INTEGRITY_ERROR) {
cons_show_error("[%s] %s — %s", level_str, issue->file, issue->message);
} else {
cons_show("[%s] %s — %s", level_str, issue->file, issue->message);
}
}
}
if (!issues) {
cons_show("Verification complete: no issues found.");
} else {
cons_show("Verification complete: %d error(s), %d warning(s), %d info(s).",
errors, warnings, infos);
g_slist_free_full(issues, (GDestroyNotify)integrity_issue_free);
}
}
gboolean
cmd_history(ProfWin* window, const char* const command, gchar** args)
{
@@ -6731,6 +6786,91 @@ cmd_history(ProfWin* window, const char* const command, gchar** args)
return TRUE;
}
if (g_strcmp0(args[0], "backend") == 0) {
if (active_db_backend && active_db_backend->name) {
cons_show("Active database backend: %s", active_db_backend->name);
} else {
cons_show("No database backend is currently active.");
}
return TRUE;
}
if (g_strcmp0(args[0], "switch") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show_error("You must be connected to switch database backend.");
return TRUE;
}
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[1], "sqlite") != 0 && g_strcmp0(args[1], "flatfile") != 0) {
cons_show_error("Backend must be 'sqlite' or 'flatfile'.");
return TRUE;
}
if (active_db_backend && g_strcmp0(active_db_backend->name, args[1]) == 0) {
cons_show("Already using '%s' backend.", args[1]);
return TRUE;
}
cons_show("Switching database backend to '%s'...", args[1]);
if (log_database_switch_backend(args[1])) {
cons_show("Database backend switched to '%s'.", args[1]);
} else {
cons_show_error("Failed to switch database backend.");
}
return TRUE;
}
if (g_strcmp0(args[0], "verify") == 0) {
const gchar* contact_jid = args[1]; // may be NULL (verify all)
cons_show("Verifying history integrity...");
GSList* issues = log_database_verify_integrity(contact_jid);
_show_integrity_issues(issues);
return TRUE;
}
if (g_strcmp0(args[0], "export") == 0) {
#ifdef HAVE_SQLITE
const gchar* contact_jid = args[1]; // may be NULL (export all)
if (contact_jid) {
cons_show("Exporting SQLite history for %s to flat-file...", contact_jid);
} else {
cons_show("Exporting all SQLite history to flat-file...");
}
int n = log_database_export_to_flatfile(contact_jid);
if (n >= 0) {
cons_show("Export complete: %d message(s) exported.", n);
}
#else
cons_show_error("Export requires SQLite support. Rebuild with --with-sqlite.");
#endif
return TRUE;
}
if (g_strcmp0(args[0], "import") == 0) {
#ifdef HAVE_SQLITE
const gchar* contact_jid = args[1]; // may be NULL (import all)
if (contact_jid) {
cons_show("Importing flat-file history for %s into SQLite...", contact_jid);
} else {
cons_show("Importing all flat-file history into SQLite...");
}
int n = log_database_import_from_flatfile(contact_jid);
if (n >= 0) {
cons_show("Import complete: %d message(s) imported.", n);
}
#else
cons_show_error("Import requires SQLite support. Rebuild with --with-sqlite.");
#endif
return TRUE;
}
_cmd_set_boolean_preference(args[0], "Chat history", PREF_HISTORY);
// if set to on, set chlog (/logging chat on)