diff options
-rw-r--r-- | src/core/settings.c | 93 | ||||
-rw-r--r-- | src/core/settings.h | 1 | ||||
-rw-r--r-- | src/fe-common/core/fe-settings.c | 32 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.c | 1 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.h | 3 |
5 files changed, 115 insertions, 15 deletions
diff --git a/src/core/settings.c b/src/core/settings.c index 96663c3b..80406261 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -35,6 +35,10 @@ static GHashTable *settings; static char *last_error_msg; static int timeout_tag; +static time_t config_last_mtime; +static long config_last_size; +static unsigned int config_last_checksum; + static const char *settings_get_default_str(const char *key) { SETTINGS_REC *rec; @@ -212,6 +216,51 @@ void sig_term(int n) raise(SIGTERM); } +/* Yes, this is my own stupid checksum generator, some "real" algorithm + would be nice but would just take more space without much real benefit */ +static unsigned int file_checksum(const char *fname) +{ + FILE *f; + int n = 0; + unsigned int checksum = 0; + + f = fopen(fname, "rb"); + while (!feof(f)) + checksum += fgetc(f) << ((n++ & 3)*8); + fclose(f); + return checksum; +} + +static void irssi_config_save_state(const char *fname) +{ + struct stat statbuf; + + g_return_if_fail(fname != NULL); + + if (stat(fname, &statbuf) != 0) + return; + + /* save modify time, file size and checksum */ + config_last_mtime = statbuf.st_mtime; + config_last_size = statbuf.st_size; + config_last_checksum = file_checksum(fname); +} + +int irssi_config_is_changed(const char *fname) +{ + struct stat statbuf; + + if (fname == NULL) + fname = mainconfig->fname; + + if (stat(fname, &statbuf) != 0) + return FALSE; + + return config_last_mtime != statbuf.st_mtime && + (config_last_size != statbuf.st_size || + config_last_checksum != file_checksum(fname)); +} + static CONFIG_REC *parse_configfile(const char *fname) { CONFIG_REC *config; @@ -239,6 +288,7 @@ static CONFIG_REC *parse_configfile(const char *fname) config_change_file_name(config, real_fname, 0660); } + irssi_config_save_state(real_fname); g_free(real_fname); return config; } @@ -323,22 +373,44 @@ int settings_reread(const char *fname) int settings_save(const char *fname) { char *str; + int error; - if (config_write(mainconfig, fname, 0660) == 0) - return TRUE; + if (fname == NULL) + fname = mainconfig->fname; - /* error */ - str = g_strdup_printf(_("Couldn't save configuration file: %s"), - config_last_error(mainconfig)); - signal_emit("gui dialog", 2, "error", str); - g_free(str); - return FALSE; + error = config_write(mainconfig, fname, 0660) != 0; + irssi_config_save_state(fname); + if (error) { + str = g_strdup_printf(_("Couldn't save " + "configuration file: %s"), + config_last_error(mainconfig)); + signal_emit("gui dialog", 2, "error", str); + g_free(str); + } + return !error; } static void sig_autosave(void) { - if (settings_get_bool("settings_autosave")) - settings_save(NULL); + char *fname, *str; + + if (!settings_get_bool("settings_autosave")) + return; + + if (!irssi_config_is_changed(NULL)) + settings_save(NULL); + else { + fname = g_strconcat(mainconfig->fname, ".autosave", NULL); + str = g_strdup_printf(_("Configuration file was modified " + "while irssi was running. Saving " + "configuration to file '%s' instead"), + fname); + signal_emit("gui dialog", 2, "warning", str); + g_free(str); + + settings_save(fname); + g_free(fname); + } } void settings_init(void) @@ -346,6 +418,7 @@ void settings_init(void) settings = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal); + config_last_mtime = 0; init_configfile(); settings_add_bool("misc", "settings_autosave", TRUE); diff --git a/src/core/settings.h b/src/core/settings.h index a887797a..8409f607 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -57,6 +57,7 @@ SETTINGS_REC *settings_get_record(const char *key); /* if `fname' is NULL, the default is used */ int settings_reread(const char *fname); int settings_save(const char *fname); +int irssi_config_is_changed(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 4c2bf823..4d8266dd 100644 --- a/src/fe-common/core/fe-settings.c +++ b/src/fe-common/core/fe-settings.c @@ -245,14 +245,38 @@ static void cmd_reload(const char *data) g_free(fname); } +static void settings_save_fe(const char *fname) +{ + if (settings_save(fname)) { + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + IRCTXT_CONFIG_SAVED, fname); + } +} + +static void settings_save_confirm(const char *line, char *fname) +{ + if (toupper(*line) == 'Y') + settings_save_fe(fname); + g_free(fname); +} + /* SYNTAX: SAVE [<file>] */ static void cmd_save(const char *data) { - if (settings_save(*data != '\0' ? data : NULL)) { - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, - IRCTXT_CONFIG_SAVED, *data != '\0' ? data : - mainconfig->fname); + if (*data == '\0') + data = mainconfig->fname; + + if (!irssi_config_is_changed(data)) { + settings_save_fe(data); + return; } + + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + IRCTXT_CONFIG_MODIFIED, data); + signal_emit("gui entry redirect", 4, + settings_save_confirm, + _("Overwrite config (y/N)?"), + GINT_TO_POINTER(FALSE), g_strdup(data)); } void fe_settings_init(void) diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index ee4c99d8..ec555ecb 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -202,6 +202,7 @@ FORMAT_REC fecommon_core_formats[] = { { "bind_unknown_id", "Unknown bind action: $0", 1, { 0 } }, { "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 } }, { NULL, NULL, 0 } }; diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h index 01390a15..362b9074 100644 --- a/src/fe-common/core/module-formats.h +++ b/src/fe-common/core/module-formats.h @@ -167,7 +167,8 @@ enum { IRCTXT_BIND_KEY, IRCTXT_BIND_UNKNOWN_ID, IRCTXT_CONFIG_SAVED, - IRCTXT_CONFIG_RELOADED + IRCTXT_CONFIG_RELOADED, + IRCTXT_CONFIG_MODIFIED }; extern FORMAT_REC fecommon_core_formats[]; |