From 9003a57c0a4aba2a5eb021c94b7c0b73a86854ad Mon Sep 17 00:00:00 2001 From: Joseph Bisch Date: Sun, 10 Sep 2017 11:56:56 -0400 Subject: [PATCH] Save backup config during /upgrade If the user has modified their config within Irssi since the config was last saved and then runs /upgrade, then we want to save a backup config (in ~/.irssi/config.clientbackup), which is reloaded upon the upgrade being done. --- src/common.h | 2 ++ src/core/core.c | 5 +++ src/core/session.c | 56 ++++++++++++++++++++++------- src/core/settings.c | 8 +++-- src/core/settings.h | 3 ++ src/fe-common/core/fe-settings.c | 11 ++++-- src/fe-common/core/module-formats.c | 1 + src/fe-common/core/module-formats.h | 1 + 8 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/common.h b/src/common.h index 100d00cb..7ade55f2 100644 --- a/src/common.h +++ b/src/common.h @@ -5,6 +5,7 @@ #define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */ #define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */ +#define IRSSI_HOME_CONFIG_BACKUP "config.clientbackup" /* config file name for upgrades */ #define IRSSI_ABI_VERSION 10 @@ -68,6 +69,7 @@ int g_input_add_full(GIOChannel *source, int priority, int condition, const char *get_irssi_dir(void); /* return full path for ~/.irssi/config */ const char *get_irssi_config(void); +void set_irssi_config(char *); /* max. size for %d */ #define MAX_INT_STRLEN ((sizeof(int) * CHAR_BIT + 2) / 3 + 1) diff --git a/src/core/core.c b/src/core/core.c index bf7cdd6b..fab27d5f 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -76,6 +76,11 @@ const char *get_irssi_config(void) return irssi_config_file; } +void set_irssi_config(char *path) +{ + irssi_config_file = path; +} + static void sig_reload_config(int signo) { reload_config = TRUE; diff --git a/src/core/session.c b/src/core/session.c index 34190c52..af85e06c 100644 --- a/src/core/session.c +++ b/src/core/session.c @@ -26,6 +26,7 @@ #include "net-sendbuffer.h" #include "pidwait.h" #include "lib-config/iconfig.h" +#include "settings.h" #include "chat-protocols.h" #include "servers.h" @@ -58,8 +59,8 @@ void session_upgrade(void) /* SYNTAX: UPGRADE [] */ static void cmd_upgrade(const char *data) { - CONFIG_REC *session; - char *session_file, *str; + CONFIG_REC *session, *config; + char *session_file, *config_file, *str; char *binary; if (*data == '\0') @@ -77,12 +78,19 @@ static void cmd_upgrade(const char *data) config_write(session, NULL, -1); config_close(session); + /* save the config */ + config_file = g_strdup_printf("%s/"IRSSI_HOME_CONFIG_BACKUP, get_irssi_dir()); + unlink(config_file); + + signal_emit("command save", 1, config_file); + /* data may contain some other program as well, like /UPGRADE /usr/bin/screen irssi */ str = g_strdup_printf("%s --noconnect --session=%s --home=%s --config=%s", - binary, session_file, get_irssi_dir(), get_irssi_config()); + binary, session_file, get_irssi_dir(), config_file); g_free(binary); g_free(session_file); + g_free(config_file); session_args = g_strsplit(str, " ", -1); g_free(str); @@ -315,20 +323,42 @@ static void sig_session_restore(CONFIG_REC *config) static void sig_init_finished(void) { - CONFIG_REC *session; + CONFIG_REC *session, *config; + char *config_file; + FILE *fp; - if (session_file == NULL) - return; + if (session_file != NULL) { + session = config_open(session_file, -1); + if (session != NULL) { + config_parse(session); + signal_emit("session restore", 1, session); + config_close(session); + } - session = config_open(session_file, -1); - if (session == NULL) - return; + unlink(session_file); + } - config_parse(session); - signal_emit("session restore", 1, session); - config_close(session); + config_file = g_strdup_printf("%s/"IRSSI_HOME_CONFIG_BACKUP, get_irssi_dir()); - unlink(session_file); + if ((fp = fopen(config_file, "r")) != NULL) { + /* load backup */ + signal_emit("command reload", 1, config_file); + backupconfig = parse_configfile(config_file); + + /* set irssi_config_file back to default so any future saves/reloads behave as expected */ + set_irssi_config(g_strdup_printf("%s/"IRSSI_HOME_CONFIG, get_irssi_dir())); + /* load regular config into mainconfig */ + signal_emit("command reload", 1, get_irssi_config()); + + /* setup mainconfig so that data from backup config is saved on next save */ + mainconfig->mainnode = backupconfig->mainnode; + mainconfig->cache = backupconfig->cache; + mainconfig->cache_nodes = backupconfig->cache_nodes; + + fclose(fp); + } + + g_free(config_file); } void session_register_options(void) diff --git a/src/core/settings.c b/src/core/settings.c index 4e0717cd..f256960b 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -34,6 +34,7 @@ #define SETTINGS_AUTOSAVE_TIMEOUT (1000*60*60) /* 1 hour */ CONFIG_REC *mainconfig; +CONFIG_REC *backupconfig = NULL; static GString *last_errors; static GSList *last_invalid_modules; @@ -673,7 +674,7 @@ static unsigned int file_checksum(const char *fname) return checksum; } -static void irssi_config_save_state(const char *fname) +void irssi_config_save_state(const char *fname) { struct stat statbuf; @@ -703,7 +704,7 @@ int irssi_config_is_changed(const char *fname) config_last_checksum != file_checksum(fname)); } -static CONFIG_REC *parse_configfile(const char *fname) +CONFIG_REC *parse_configfile(const char *fname) { CONFIG_REC *config; struct stat statbuf; @@ -827,6 +828,9 @@ int settings_save(const char *fname, int autosave) g_free(str); } signal_emit("setup saved", 2, fname, GINT_TO_POINTER(autosave)); + if (backupconfig != NULL && backupconfig->fname != NULL) { + unlink(backupconfig->fname); + } return !error; } diff --git a/src/core/settings.h b/src/core/settings.h index d174f250..96bcfd14 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -51,6 +51,7 @@ typedef struct { #define iconfig_node_add_list(a, b) config_node_add_list(mainconfig, a, b) extern struct _CONFIG_REC *mainconfig; +extern struct _CONFIG_REC *backupconfig; extern const char *default_config; /* Functions for handling the "settings" node of Irssi configuration */ @@ -123,7 +124,9 @@ void settings_clean_invalid(void); /* if `fname' is NULL, the default is used */ int settings_reread(const char *fname); int settings_save(const char *fname, int autosave); +void irssi_config_save_state(const char *fname); int irssi_config_is_changed(const char *fname); +struct _CONFIG_REC *parse_configfile(const char *fname); void settings_init(void); void settings_deinit(void); diff --git a/src/fe-common/core/fe-settings.c b/src/fe-common/core/fe-settings.c index abbd45a8..ddd1a690 100644 --- a/src/fe-common/core/fe-settings.c +++ b/src/fe-common/core/fe-settings.c @@ -364,9 +364,12 @@ static void cmd_save(const char *data) if (*fname == '\0') fname = mainconfig->fname; - if (!irssi_config_is_changed(fname)) - settings_save_fe(fname); - else { + if (irssi_config_is_changed(fname) && backupconfig != NULL) { + /* config file modified outside irssi and backup config exists */ + /* must not save and direct user to merge files outside of irssi */ + printformat(NULL,NULL, MSGLEVEL_CLIENTNOTICE, + TXT_CONFIG_CONFLICT, fname, backupconfig->fname); + } else if (irssi_config_is_changed(fname)) { /* config file modified outside irssi */ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CONFIG_MODIFIED, fname); @@ -376,6 +379,8 @@ static void cmd_save(const char *data) keyboard_entry_redirect((SIGNAL_FUNC) settings_save_confirm, format, 0, g_strdup(fname)); g_free(format); + } else { + settings_save_fe(fname); } cmd_params_free(free_arg); diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index da9705be..b2ca6df8 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -279,6 +279,7 @@ FORMAT_REC fecommon_core_formats[] = { { "config_saved", "Saved configuration to file $0", 1, { 0 } }, { "config_reloaded", "Reloaded configuration", 1, { 0 } }, { "config_modified", "Configuration file was modified since irssi was last started - do you want to overwrite the possible changes?", 1, { 0 } }, + { "config_conflict", "Configuration file was modified since irssi was last started and backup config from upgrade exists - please use external merge tool to merge $0 and $1 into $0. Config was not saved.", 2, { 0, 0 } }, { "glib_error", "{error $0} $1", 2, { 0, 0 } }, { "overwrite_config", "Overwrite config (y/N)?", 0 }, { "set_title", "[{hilight $0}]", 1, { 0 } }, diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h index f361befb..0ed33789 100644 --- a/src/fe-common/core/module-formats.h +++ b/src/fe-common/core/module-formats.h @@ -244,6 +244,7 @@ enum { TXT_CONFIG_SAVED, TXT_CONFIG_RELOADED, TXT_CONFIG_MODIFIED, + TXT_CONFIG_CONFLICT, TXT_GLIB_ERROR, TXT_OVERWRITE_CONFIG, TXT_SET_TITLE,