/* profile.c * Storage of profile information * Stig Bjorlykke , 2008 * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include #include #include #include "profile.h" static GList *edited_profiles; GList * profile_get_list(void) { return g_list_first(edited_profiles); } static void load_profile_settings(profile_def *profile, const char* app_env_var_prefix); static GList * add_profile_entry(GList *fl, const char *profilename, const char *reference, bool is_global, const char* auto_switch_filter) { profile_def *profile; profile = g_new0(profile_def, 1); profile->name = g_strdup(profilename); profile->reference = g_strdup(reference); profile->auto_switch_filter = g_strdup(auto_switch_filter ? auto_switch_filter : ""); profile->is_global = is_global; return g_list_append(fl, profile); } GList* profile_add_profile(const char* name, const char* expression, bool is_global, const char* auto_switch_filter) { edited_profiles = add_profile_entry(edited_profiles, name, expression, is_global, auto_switch_filter); return g_list_last(edited_profiles); } static void remove_profile_entry(profile_def* profile) { g_free(profile->name); g_free(profile->reference); g_free(profile->auto_switch_filter); g_free(profile); } static profile_def* profile_find_by_name(const char* name, bool is_global) { GList *iter; for (iter = g_list_first(edited_profiles); iter; iter = g_list_next(iter)) { profile_def* profile = (profile_def*)iter->data; if (strcmp(profile->name, name) == 0 && profile->is_global == is_global) { return profile; } } return NULL; } static bool profile_name_is_valid(const char* name) { bool valid = true; #ifdef _WIN32 char* invalid_dir_char = "\\/:*?\"<>|"; int i; for (i = 0; i < 9; i++) { if (strchr(name, invalid_dir_char[i])) { /* Invalid character in directory */ valid = false; } } if (name[0] == '.' || name[strlen(name) - 1] == '.') { /* Profile name cannot start or end with period */ valid = false; } #else if (strchr(name, '/')) { /* Invalid character in directory */ valid = false; } #endif return valid; } /* Get (sorted) list of profiles in a directory */ static GList* get_profiles(const char* directory) { WS_DIR *dir; /* scanned directory */ WS_DIRENT *file; /* current file */ const char *name; GList *profiles = NULL; char *filename; if ((dir = ws_dir_open(directory, 0, NULL)) != NULL) { while ((file = ws_dir_read_name(dir)) != NULL) { name = ws_dir_get_name(file); if (!profile_name_is_valid(name)) //Skip directories that are not valid profile names continue; filename = ws_strdup_printf ("%s%s%s", directory, G_DIR_SEPARATOR_S, name); if (test_for_directory(filename) == EISDIR) profiles = g_list_prepend(profiles, g_strdup(name)); g_free(filename); } ws_dir_close(dir); } profiles = g_list_sort(profiles, (GCompareFunc)g_ascii_strcasecmp); return profiles; } void profile_init(const char* app_env_var_prefix) { const char *name; GList *local_profiles = NULL; GList *global_profiles = NULL; GList *iter, *item; char *profiles_dir; /* Default entry */ item = profile_add_profile(DEFAULT_PROFILE, DEFAULT_PROFILE, false, ""); load_profile_settings((profile_def *)item->data, app_env_var_prefix); /* Local (user) profiles */ profiles_dir = get_profiles_dir(app_env_var_prefix); local_profiles = get_profiles(profiles_dir); g_free(profiles_dir); for (iter = g_list_first(local_profiles); iter; iter = g_list_next(iter)) { name = (char *)iter->data; item = profile_add_profile(name, name, false, ""); load_profile_settings((profile_def *)item->data, app_env_var_prefix); } g_list_free_full(local_profiles, g_free); /* Global profiles */ profiles_dir = get_global_profiles_dir(app_env_var_prefix); global_profiles = get_profiles(profiles_dir); g_free(profiles_dir); for (iter = g_list_first(global_profiles); iter; iter = g_list_next(iter)) { name = (char *)iter->data; item = profile_add_profile(name, name, true, ""); load_profile_settings((profile_def *)item->data, app_env_var_prefix); } g_list_free_full(global_profiles, g_free); } void profile_sync(const char* app_env_var_prefix) { const char* name; char* profiles_dir; GList *local_profiles = NULL, *global_profiles = NULL; GList *iter, *lp_iter, *gp_iter; /* Local (user) profiles */ profiles_dir = get_profiles_dir(app_env_var_prefix); local_profiles = get_profiles(profiles_dir); g_free(profiles_dir); /* Global profiles */ profiles_dir = get_global_profiles_dir(app_env_var_prefix); global_profiles = get_profiles(profiles_dir); g_free(profiles_dir); /* * Look for profiles that no longer have a directory and remove them */ iter = g_list_first(edited_profiles); /* Always skip the default profile (first) */ iter = g_list_next(iter); while (iter) { profile_def* profile = (profile_def*)iter->data; bool found = false; for (lp_iter = g_list_first(local_profiles); lp_iter; lp_iter = g_list_next(lp_iter)) { name = (char*)lp_iter->data; if (strcmp(profile->name, name) == 0 && !profile->is_global) { found = true; break; } } if (!found) { for (gp_iter = g_list_first(global_profiles); gp_iter; gp_iter = g_list_next(gp_iter)) { name = (char*)gp_iter->data; if (strcmp(profile->name, name) == 0 && profile->is_global) { found = true; break; } } } GList* next = g_list_next(iter); if (!found) { edited_profiles = g_list_remove(edited_profiles, profile); remove_profile_entry(profile); } iter = next; } /* * Now add profiles that are new */ for (lp_iter = g_list_first(local_profiles); lp_iter; lp_iter = g_list_next(lp_iter)) { name = (char*)lp_iter->data; if (profile_find_by_name(name, false) == NULL) { GList* item = profile_add_profile(name, name, false, ""); load_profile_settings((profile_def *)item->data, app_env_var_prefix); } } for (gp_iter = g_list_first(global_profiles); gp_iter; gp_iter = g_list_next(gp_iter)) { name = (char*)gp_iter->data; if (profile_find_by_name(name, true) == NULL) { GList* item = profile_add_profile(name, name, true, ""); load_profile_settings((profile_def*)item->data, app_env_var_prefix); } } /* Clean up */ g_list_free_full(local_profiles, g_free); g_list_free_full(global_profiles, g_free); } bool profile_delete_current(const char* app_env_var_prefix, char** err_info) { const char *name = get_profile_name(); char *pf_dir_path; if (profile_exists(app_env_var_prefix, name, false) && strcmp (name, DEFAULT_PROFILE) != 0) { if (delete_persconffile_profile(app_env_var_prefix, name, &pf_dir_path) == -1) { *err_info = g_strdup_printf("Can't delete profile directory\n\"%s\":\n%s.", pf_dir_path, g_strerror(errno)); g_free(pf_dir_path); } else { //Remove the profile from the list GList* item = edited_profiles; while (item != NULL) { profile_def* profile = (profile_def*)item->data; if (strcmp(profile->name, name) == 0) { edited_profiles = g_list_remove(edited_profiles, profile); remove_profile_entry(profile); break; } item = g_list_next(item); } return true; } } return false; } void profile_empty_list(void) { GList** flpp = &edited_profiles; while (*flpp) { GList* first = g_list_first(*flpp); profile_def* profile = first->data; remove_profile_entry(profile); *flpp = g_list_remove_link(*flpp, first); g_list_free_1(first); } edited_profiles = NULL; } // Use a settings file in case we ever want to include an author, description, // URL, etc. #define PROFILE_SETTINGS_FILENAME "profile_settings" #define AUTO_SWITCH_FILTER_KEY "auto_switch_filter" static char *get_profile_settings_path(const char *profile_name, bool is_global, const char* app_env_var_prefix) { char *profile_settings_path; char *profile_dir = get_profile_dir(app_env_var_prefix, profile_name, is_global); profile_settings_path = g_build_filename(profile_dir, PROFILE_SETTINGS_FILENAME, NULL); g_free(profile_dir); return profile_settings_path; } /* Set */ static prefs_set_pref_e set_profile_setting(char *key, const char *value, void *profile_ptr, bool return_range_errors _U_) { profile_def *profile = (profile_def *) profile_ptr; if (strcmp(key, AUTO_SWITCH_FILTER_KEY) == 0) { g_free(profile->auto_switch_filter); profile->auto_switch_filter = g_strdup(value); } return PREFS_SET_OK; } static void load_profile_settings(profile_def *profile, const char* app_env_var_prefix) { char *profile_settings_path = get_profile_settings_path(profile->name, profile->is_global, app_env_var_prefix); FILE *fp; if ((fp = ws_fopen(profile_settings_path, "r")) != NULL) { read_prefs_file(profile_settings_path, fp, set_profile_setting, profile); fclose(fp); } g_free(profile_settings_path); } bool profile_save_settings(const char* name, const char* app_env_var_prefix, const char* app_name, char** err_info) { profile_def* profile = NULL; GList *fl1 = profile_get_list(); while (fl1) { if (strcmp(((profile_def*)fl1->data)->name, name) == 0) { profile = (profile_def*)fl1->data; break; } fl1 = g_list_next(fl1); } //Didn't find the profile if (profile == NULL) { *err_info = g_strdup_printf("Can't find profile %s\n.", name); return false; } char *profile_settings_path = get_profile_settings_path(profile->name, false, app_env_var_prefix); FILE *fp; if ((fp = ws_fopen(profile_settings_path, "w")) == NULL) { *err_info = g_strdup_printf("Can't open recent file\n\"%s\": %s.", profile_settings_path, g_strerror(errno)); g_free(profile_settings_path); return false; } g_free(profile_settings_path); fprintf(fp, "# \"%s\" profile settings file for %s " VERSION ". Edit with care.\n", profile->name, app_name); fprintf(fp, "\n# Automatically switch to this profile if this display filter matches.\n"); fprintf(fp, AUTO_SWITCH_FILTER_KEY ": %s\n", profile->auto_switch_filter); fclose(fp); return true; }