From f9c04a2c4c0e4b94202d3b522bdcbd3f5cbadcc9 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Tue, 4 Jun 2019 01:43:35 +0200 Subject: [PATCH] Added ephemeral mode #562. If vimb is started with --ephemeral option no files are created by default and no persistent cookie manager is used. --- src/bookmark.c | 7 +++++- src/ex.c | 2 +- src/file-storage.c | 30 +++++++++++++------------ src/file-storage.h | 2 ++ src/history.c | 47 ++++++++++++++++++++++----------------- src/main.c | 28 ++++++++++++++--------- src/main.h | 15 ++++++++++--- src/setting.c | 4 ++-- src/util.c | 44 +++--------------------------------- src/util.h | 3 +-- tests/test-file-storage.c | 16 ++++++++++--- 11 files changed, 100 insertions(+), 98 deletions(-) diff --git a/src/bookmark.c b/src/bookmark.c index 72c76a89..2a0a3cf9 100644 --- a/src/bookmark.c +++ b/src/bookmark.c @@ -236,7 +236,12 @@ gboolean bookmark_queue_clear(void) static GList *load(const char *file) { - return util_file_to_unique_list(file, (Util_Content_Func)line_to_bookmark, 0); + char **lines; + GList *list; + lines = util_get_lines(file); + list = util_strv_to_unique_list(lines, (Util_Content_Func)line_to_bookmark, 0); + g_strfreev(lines); + return list; } /** diff --git a/src/ex.c b/src/ex.c index 708020dc..d67c05a0 100644 --- a/src/ex.c +++ b/src/ex.c @@ -956,7 +956,7 @@ static VbCmdResult ex_queue(Client *c, const ExArg *arg) return command_queue(c, &a) ? CMD_SUCCESS | CMD_KEEPINPUT - : CMD_ERROR | CMD_KEEPINPUT; + : CMD_ERROR; } #endif diff --git a/src/file-storage.c b/src/file-storage.c index a9244823..98b7f99f 100644 --- a/src/file-storage.c +++ b/src/file-storage.c @@ -23,7 +23,6 @@ #include #include "file-storage.h" -#include "util.h" struct filestorage { char *file_path; @@ -44,26 +43,19 @@ struct filestorage { * creating it. If 0 the file is not created and the storage is * used in read only mode - no data written to the file. */ -FileStorage *file_storage_new(const char *dir, const char *filename, int mode) +FileStorage *file_storage_new(const char *dir, const char *filename, gboolean readonly) { - char *fullpath; FileStorage *storage; - storage = g_slice_new(FileStorage); - storage->readonly = (mode == 0); - - /* Built the full path out of dir and given file name. */ - fullpath = g_build_filename(dir, filename, NULL); - if (!g_file_test(fullpath, G_FILE_TEST_IS_REGULAR) && mode) { - /* If create option was given - create the file. */ - fclose(fopen(fullpath, "a")); - g_chmod(fullpath, mode); - } - storage->file_path = fullpath; + storage = g_slice_new(FileStorage); + storage->readonly = readonly; + storage->file_path = g_build_filename(dir, filename, NULL); /* Use gstring as storage in case when the file is used read only. */ if (storage->readonly) { storage->str = g_string_new(NULL); + } else { + storage->str = NULL; } return storage; @@ -147,3 +139,13 @@ char **file_storage_get_lines(FileStorage *storage) return lines; } + +const char *file_storage_get_path(FileStorage *storage) +{ + return storage->file_path; +} + +gboolean file_storage_is_readonly(FileStorage *storage) +{ + return storage->readonly; +} diff --git a/src/file-storage.h b/src/file-storage.h index 3beecce4..4a26a8fa 100644 --- a/src/file-storage.h +++ b/src/file-storage.h @@ -27,5 +27,7 @@ FileStorage *file_storage_new(const char *dir, const char *filename, int mode); void file_storage_free(FileStorage *storage); gboolean file_storage_append(FileStorage *storage, const char *format, ...); char **file_storage_get_lines(FileStorage *storage); +const char *file_storage_get_path(FileStorage *storage); +gboolean file_storage_is_readonly(FileStorage *storage); #endif /* end of include guard: _FILE_STORAGE_H */ diff --git a/src/history.c b/src/history.c index 91246054..250333b9 100644 --- a/src/history.c +++ b/src/history.c @@ -27,8 +27,9 @@ #include "history.h" #include "main.h" #include "util.h" +#include "file-storage.h" -#define HIST_FILE(t) (vb.files[file_map[t]]) +#define HIST_STORAGE(t) (vb.storage[storage_map[t]]) typedef struct { char *first; char *second; @@ -37,14 +38,14 @@ typedef struct { static gboolean history_item_contains_all_tags(History *item, char **query, guint qlen); static void free_history(History *item); static History *line_to_history(const char *uri, const char *title); -static GList *load(const char *file); +static GList *load(FileStorage *s); static void write_to_file(GList *list, const char *file); /* map history types to files */ -static const int file_map[HISTORY_LAST] = { - FILES_COMMAND, - FILES_SEARCH, - FILES_HISTORY +static const int storage_map[HISTORY_LAST] = { + STORAGE_COMMAND, + STORAGE_SEARCH, + STORAGE_HISTORY }; extern struct Vimb vb; @@ -53,18 +54,18 @@ extern struct Vimb vb; */ void history_add(Client *c, HistoryType type, const char *value, const char *additional) { - const char *file; + FileStorage *s; /* Don't write a history entry if the history max size is set to 0. */ if (!vb.config.history_max) { return; } - file = HIST_FILE(type); + s = HIST_STORAGE(type); if (additional) { - util_file_append(file, "%s\t%s\n", value, additional); + file_storage_append(s, "%s\t%s\n", value, additional); } else { - util_file_append(file, "%s\n", value); + file_storage_append(s, "%s\n", value); } } @@ -74,7 +75,7 @@ void history_add(Client *c, HistoryType type, const char *value, const char *add */ void history_cleanup(void) { - const char *file; + FileStorage *s; GList *list; /* don't cleanup the history file if history max size is 0 */ @@ -83,10 +84,12 @@ void history_cleanup(void) } for (HistoryType i = HISTORY_FIRST; i < HISTORY_LAST; i++) { - file = HIST_FILE(i); - list = load(file); - write_to_file(list, file); - g_list_free_full(list, (GDestroyNotify)free_history); + s = HIST_STORAGE(i); + if (!file_storage_is_readonly(s)) { + list = load(s); + write_to_file(list, file_storage_get_path(s)); + g_list_free_full(list, (GDestroyNotify)free_history); + } } } @@ -99,7 +102,7 @@ gboolean history_fill_completion(GtkListStore *store, HistoryType type, const ch GtkTreeIter iter; History *item; - src = load(HIST_FILE(type)); + src = load(HIST_STORAGE(type)); src = g_list_reverse(src); if (!input || !*input) { /* without any tags return all items */ @@ -168,12 +171,12 @@ GList *history_get_list(VbInputType type, const char *query) switch (type) { case INPUT_COMMAND: - src = load(HIST_FILE(HISTORY_COMMAND)); + src = load(HIST_STORAGE(HISTORY_COMMAND)); break; case INPUT_SEARCH_FORWARD: case INPUT_SEARCH_BACKWARD: - src = load(HIST_FILE(HISTORY_SEARCH)); + src = load(HIST_STORAGE(HISTORY_SEARCH)); break; default: @@ -241,10 +244,12 @@ static History *line_to_history(const char *uri, const char *title) * * Returned list must be freed with (GDestroyNotify)free_history. */ -static GList *load(const char *file) +static GList *load(FileStorage *s) { - return util_file_to_unique_list( - file, (Util_Content_Func)line_to_history, vb.config.history_max + return util_strv_to_unique_list( + file_storage_get_lines(s), + (Util_Content_Func)line_to_history, + vb.config.history_max ); } diff --git a/src/main.c b/src/main.c index 6a228a18..00d12cf3 100644 --- a/src/main.c +++ b/src/main.c @@ -46,6 +46,7 @@ #include "shortcut.h" #include "util.h" #include "autocmd.h" +#include "file-storage.h" static void client_destroy(Client *c); static Client *client_new(WebKitWebView *webview); @@ -1768,6 +1769,9 @@ static void vimb_cleanup(void) /* free memory of other components */ util_cleanup(); + for (i = 0; i < STORAGE_LAST; i++) { + file_storage_free(vb.storage[i]); + } for (i = 0; i < FILES_LAST; i++) { if (vb.files[i]) { g_free(vb.files[i]); @@ -1794,19 +1798,22 @@ static void vimb_setup(void) vb.files[FILES_CONFIG] = g_strdup(rp); free(rp); } else { - vb.files[FILES_CONFIG] = util_get_filepath(path, "config", FALSE, 0600); + vb.files[FILES_CONFIG] = g_build_filename(path, "config", NULL); } /* Setup those files that are use multiple time during runtime */ - vb.files[FILES_CLOSED] = util_get_filepath(path, "closed", TRUE, 0600); - vb.files[FILES_COOKIE] = util_get_filepath(path, "cookies.db", TRUE, 0600); - vb.files[FILES_USER_STYLE] = util_get_filepath(path, "style.css", FALSE, 0600); - vb.files[FILES_SCRIPT] = util_get_filepath(path, "scripts.js", FALSE, 0600); - vb.files[FILES_HISTORY] = util_get_filepath(path, "history", TRUE, 0600); - vb.files[FILES_COMMAND] = util_get_filepath(path, "command", TRUE, 0600); - vb.files[FILES_BOOKMARK] = util_get_filepath(path, "bookmark", TRUE, 0600); - vb.files[FILES_QUEUE] = util_get_filepath(path, "queue", TRUE, 0600); - vb.files[FILES_SEARCH] = util_get_filepath(path, "search", TRUE, 0600); + if (!vb.ephemeral) { + vb.files[FILES_CLOSED] = g_build_filename(path, "closed", NULL); + vb.files[FILES_COOKIE] = g_build_filename(path, "cookies.db", NULL); + } + vb.files[FILES_BOOKMARK] = g_build_filename(path, "bookmark", NULL); + vb.files[FILES_QUEUE] = g_build_filename(path, "queue", NULL); + vb.files[FILES_SCRIPT] = g_build_filename(path, "scripts.js", NULL); + vb.files[FILES_USER_STYLE] = g_build_filename(path, "style.css", NULL); + + vb.storage[STORAGE_HISTORY] = file_storage_new(path, "history", vb.ephemeral); + vb.storage[STORAGE_COMMAND] = file_storage_new(path, "command", vb.ephemeral); + vb.storage[STORAGE_SEARCH] = file_storage_new(path, "search", vb.ephemeral); g_free(path); /* Use seperate rendering processed for the webview of the clients in the @@ -2066,6 +2073,7 @@ int main(int argc, char* argv[]) GOptionEntry opts[] = { {"config", 'c', 0, G_OPTION_ARG_FILENAME, &vb.configfile, "Custom configuration file", NULL}, + {"ephemeral", 'E', 0, G_OPTION_ARG_NONE, &vb.ephemeral, "Run in ephemeral mode", NULL}, {"embed", 'e', 0, G_OPTION_ARG_STRING, &winid, "Reparents to window specified by xid", NULL}, {"profile", 'p', 0, G_OPTION_ARG_CALLBACK, (GOptionArgFunc*)profileOptionArgFunc, "Profile name", NULL}, {"version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Print version", NULL}, diff --git a/src/main.h b/src/main.h index 9e922c65..616d39c1 100644 --- a/src/main.h +++ b/src/main.h @@ -26,6 +26,7 @@ #include #include "shortcut.h" #include "handler.h" +#include "file-storage.h" #include "config.h" @@ -105,17 +106,23 @@ typedef enum { enum { FILES_BOOKMARK, FILES_CLOSED, - FILES_COMMAND, FILES_CONFIG, FILES_COOKIE, - FILES_HISTORY, FILES_QUEUE, FILES_SCRIPT, - FILES_SEARCH, FILES_USER_STYLE, FILES_LAST }; +enum { + STORAGE_CLOSED, + STORAGE_COMMAND, + STORAGE_CONFIG, + STORAGE_HISTORY, + STORAGE_SEARCH, + STORAGE_LAST +}; + typedef enum { LINK_TYPE_NONE, LINK_TYPE_LINK, @@ -268,6 +275,7 @@ struct Vimb { GHashTable *modes; /* all available browser main modes */ char *configfile; /* config file given as option on startup */ char *files[FILES_LAST]; + FileStorage *storage[STORAGE_LAST]; char *profile; /* profile name */ struct { guint history_max; @@ -275,6 +283,7 @@ struct Vimb { } config; GtkCssProvider *style_provider; gboolean no_maximize; + gboolean ephemeral; }; gboolean vb_download_set_destination(Client *c, WebKitDownload *download, diff --git a/src/setting.c b/src/setting.c index 07218ba0..b73bc182 100644 --- a/src/setting.c +++ b/src/setting.c @@ -674,7 +674,7 @@ static int user_style(Client *c, const char *name, DataType type, void *value, v ucm = webkit_web_view_get_user_content_manager(c->webview); - if (enabled && vb.files[FILES_USER_STYLE]) { + if (enabled) { if (g_file_get_contents(vb.files[FILES_USER_STYLE], &source, NULL, NULL)) { style = webkit_user_style_sheet_new( source, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, @@ -685,7 +685,7 @@ static int user_style(Client *c, const char *name, DataType type, void *value, v webkit_user_style_sheet_unref(style); g_free(source); } else { - g_warning("Could not reed style file: %s", vb.files[FILES_USER_STYLE]); + g_message("Could not reed style file: %s", vb.files[FILES_USER_STYLE]); } } else { webkit_user_content_manager_remove_all_style_sheets(ucm); diff --git a/src/util.c b/src/util.c index 4cc50a07..94c98003 100644 --- a/src/util.c +++ b/src/util.c @@ -429,41 +429,6 @@ gboolean util_file_set_content(const char *file, const char *contents) return retval; } -/** - * Buil the path from given directory and filename and checks if the file - * exists. If the file does not exists and the create option is not set, this - * function returns NULL. - * If the file exists or the create option was given the full generated path - * is returned as newly allocated string. - * - * The return value must be freed with g_free. - * - * @dir: Directory in which the file is searched. - * @filename: Filename to built the absolute path with. - * @create: If TRUE, the file is created if it does not already exist. - * @mode: Mode (file permission as chmod(2)) used for the file when creating it. - */ -char *util_get_filepath(const char *dir, const char *filename, gboolean create, int mode) -{ - char *fullpath; - - /* Built the full path out of config dir and given file name. */ - fullpath = g_build_filename(dir, filename, NULL); - - if (g_file_test(fullpath, G_FILE_TEST_IS_REGULAR)) { - return fullpath; - } else if (create) { - /* If create option was given - create the file. */ - fclose(fopen(fullpath, "a")); - g_chmod(fullpath, mode); - return fullpath; - } - - g_free(fullpath); - return NULL; -} - - /** * Retrieves the file content as lines. * @@ -478,7 +443,7 @@ char **util_get_lines(const char *filename) return NULL; } - if ((content = util_get_file_contents(filename, NULL))) { + if (g_file_get_contents(filename, &content, NULL, NULL)) { /* split the file content into lines */ lines = g_strsplit(content, "\n", -1); g_free(content); @@ -491,20 +456,18 @@ char **util_get_lines(const char *filename) * based on the lines comparing all chars until the next char or end of * line. * - * @filename: file to read items from * @func: Function to parse a single line to item. * @max_items: maximum number of items that are returned, use 0 for * unlimited items */ -GList *util_file_to_unique_list(const char *filename, Util_Content_Func func, +GList *util_strv_to_unique_list(char **lines, Util_Content_Func func, guint max_items) { - char *line, **lines; + char *line; int i, len; GList *gl = NULL; GHashTable *ht; - lines = util_get_lines(filename); if (!lines) { return NULL; } @@ -556,7 +519,6 @@ GList *util_file_to_unique_list(const char *filename, Util_Content_Func func, } } - g_strfreev(lines); g_hash_table_destroy(ht); return gl; diff --git a/src/util.h b/src/util.h index 62b75743..7edea553 100644 --- a/src/util.h +++ b/src/util.h @@ -43,9 +43,8 @@ char *util_file_pop_line(const char *file, int *item_count); char *util_get_config_dir(void); char *util_get_file_contents(const char *filename, gsize *length); gboolean util_file_set_content(const char *file, const char *contents); -char *util_get_filepath(const char *dir, const char *filename, gboolean create, int mode); char **util_get_lines(const char *filename); -GList *util_file_to_unique_list(const char *filename, Util_Content_Func func, +GList *util_strv_to_unique_list(char **lines, Util_Content_Func func, guint max_items); gboolean util_fill_completion(GtkListStore *store, const char *input, GList *src); gboolean util_filename_fill_completion(State state, GtkListStore *store, const char *input); diff --git a/tests/test-file-storage.c b/tests/test-file-storage.c index 9cea8721..387905b5 100644 --- a/tests/test-file-storage.c +++ b/tests/test-file-storage.c @@ -36,8 +36,10 @@ static void test_ephemeral_no_file(void) /* make sure the file does not exist */ remove(file_path); - s = file_storage_new(pwd, none_existing_file, 0); + s = file_storage_new(pwd, none_existing_file, TRUE); g_assert_nonnull(s); + g_assert_cmpstr(file_path, ==, file_storage_get_path(s)); + g_assert_true(file_storage_is_readonly(s)); /* empty file storage */ lines = file_storage_get_lines(s); @@ -68,7 +70,13 @@ static void test_file_created(void) remove(file_path); g_assert_false(g_file_test(file_path, G_FILE_TEST_IS_REGULAR)); - s = file_storage_new(pwd, created_file, 0640); + s = file_storage_new(pwd, created_file, FALSE); + g_assert_false(file_storage_is_readonly(s)); + g_assert_cmpstr(file_path, ==, file_storage_get_path(s)); + + /* check that file is created only on first write */ + g_assert_false(g_file_test(file_path, G_FILE_TEST_IS_REGULAR)); + file_storage_append(s, ""); g_assert_true(g_file_test(file_path, G_FILE_TEST_IS_REGULAR)); file_storage_free(s); @@ -85,8 +93,10 @@ static void test_ephemeral_with_file(void) file_path = g_build_filename(pwd, existing_file, NULL); - s = file_storage_new(pwd, existing_file, 0); + s = file_storage_new(pwd, existing_file, TRUE); g_assert_nonnull(s); + g_assert_true(file_storage_is_readonly(s)); + g_assert_cmpstr(file_path, ==, file_storage_get_path(s)); /* file does not exists yet */ lines = file_storage_get_lines(s);