Something went wrong. Try again.
A modern, network-enabled music player platform built on Rockbox technology. rockboxd.tsiry-sandratraina.com
rust deno navidrome airplay libadwaita zig mpris snapcast mpd rockbox audio subsonic
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/
#include "plugin.h"#include "lib/configfile.h"
/* taken from apps/gui/wps_parser.c */#define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps"#define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps"
#define CONFIG_FILENAME "theme_remove.cfg"#define LOG_FILENAME "/theme_remove_log.txt"#define RB_FONTS_CONFIG VIEWERS_DIR "/rockbox-fonts.config"
enum remove_option { ALWAYS_REMOVE, NEVER_REMOVE, REMOVE_IF_NOT_USED, ASK_FOR_REMOVAL, NUM_REMOVE_OPTION};
struct remove_setting { const char *name; const char *prefix, *suffix; char value[MAX_PATH]; int option; int (*func)(struct remove_setting *); bool used;};
static int remove_wps(struct remove_setting *);static int remove_icons(struct remove_setting *setting);
enum remove_settings { REMOVE_FONT, REMOVE_WPS, REMOVE_SBS,#ifdef HAVE_REMOTE_LCD REMOVE_RWPS, REMOVE_RSBS,#endif#if LCD_DEPTH > 1 REMOVE_BACKDROP,#endif REMOVE_ICON, REMOVE_VICON,#ifdef HAVE_REMOTE_LCD REMOVE_RICON, REMOVE_RVICON,#endif#ifdef HAVE_LCD_COLOR REMOVE_COLOURS,#endif NUM_REMOVE_ITEMS};
static bool create_log = true;static struct remove_setting remove_list[NUM_REMOVE_ITEMS] = { [REMOVE_FONT] = { "font", FONT_DIR "/", ".fnt", "", ASK_FOR_REMOVAL, NULL, false }, [REMOVE_WPS] = { "wps", WPS_DIR "/", ".wps", "", REMOVE_IF_NOT_USED, remove_wps, false }, [REMOVE_SBS] = { "sbs", SBS_DIR "/", ".sbs", "", REMOVE_IF_NOT_USED, remove_wps, false },#ifdef HAVE_REMOTE_LCD [REMOVE_RWPS] = { "rwps", WPS_DIR "/", ".rwps", "", REMOVE_IF_NOT_USED, remove_wps, false }, [REMOVE_RSBS] = { "rsbs", SBS_DIR "/", ".rsbs", "", REMOVE_IF_NOT_USED, remove_wps, false },#endif#if LCD_DEPTH > 1 [REMOVE_BACKDROP] = { "backdrop", BACKDROP_DIR "/", ".bmp", "", REMOVE_IF_NOT_USED, NULL, false },#endif [REMOVE_ICON] = { "iconset", ICON_DIR "/", ".bmp", "", ASK_FOR_REMOVAL, NULL, false }, [REMOVE_VICON] = { "viewers iconset", ICON_DIR "/", ".bmp", "", ASK_FOR_REMOVAL, remove_icons, false },#ifdef HAVE_REMOTE_LCD [REMOVE_RICON] = { "remote iconset", ICON_DIR "/", ".bmp", "", ASK_FOR_REMOVAL, NULL, false }, [REMOVE_RVICON] = { "remote viewers iconset", ICON_DIR "/", ".bmp", "", ASK_FOR_REMOVAL, NULL, false },#endif#ifdef HAVE_LCD_COLOR [REMOVE_COLOURS] = { "filetype colours", THEME_DIR "/", ".colours", "", ASK_FOR_REMOVAL, NULL, false },#endif};static char *option_names[NUM_REMOVE_OPTION] = { "always", "never", "not used", "ask",};static struct configdata config[] = { { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_FONT].option }, "remove font", option_names }, { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_WPS].option }, "remove wps", option_names }, { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_SBS].option }, "remove sbs", option_names },#ifdef HAVE_REMOTE_LCD { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_RWPS].option }, "remove rwps", option_names }, { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_RSBS].option }, "remove rsbs", option_names },#endif#if LCD_DEPTH > 1 { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_BACKDROP].option }, "remove backdrop", option_names },#endif { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_ICON].option }, "remove iconset", option_names }, { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_VICON].option }, "remove viconset", option_names },#ifdef HAVE_REMOTE_LCD { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_RICON].option }, "remove riconset", option_names }, { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_RVICON].option }, "remove rviconset", option_names },#endif#ifdef HAVE_LCD_COLOR { TYPE_INT, 0, NUM_REMOVE_OPTION, { .int_p = &remove_list[REMOVE_COLOURS].option }, "remove colours", option_names },#endif {TYPE_BOOL, 0, 1, { .bool_p = &create_log }, "create log", NULL},};static const int nb_config = sizeof(config)/sizeof(*config);static char themefile[MAX_PATH];static int log_fd = -1;
static int show_mess(const char *text, const char *file){ static char buf[MAX_PATH*2];
if (file) rb->snprintf(buf, sizeof(buf), "%s: %s", text, file); else rb->snprintf(buf, sizeof(buf), "%s", text);
DEBUGF("%s\n", buf); if (log_fd >= 0) rb->fdprintf(log_fd, "%s\n", buf);
rb->splash(0, buf); rb->sleep(HZ/4);
return 0;}
/* set full path of file. */static void set_file_name(char *buf, const char*file, struct remove_setting *setting){ int len1, len2; if (rb->strncasecmp(file, setting->prefix, rb->strlen(setting->prefix))) rb->snprintf(buf, MAX_PATH, "%s%s", setting->prefix, file); else rb->strlcpy(buf, file, MAX_PATH); len1 = rb->strlen(buf); len2 = rb->strlen(setting->suffix); if (rb->strcasecmp(buf+len1-len2, setting->suffix)) rb->strlcpy(&buf[len1], setting->suffix, MAX_PATH-len1);}
/* taken from apps/onplay.c *//* helper function to remove a non-empty directory */static int remove_dir(char* dirname, int len){ int result = 0; DIR* dir; int dirlen = rb->strlen(dirname);
dir = rb->opendir(dirname); if (!dir) return -1; /* open error */
while (true) { struct dirent* entry; /* walk through the directory content */ entry = rb->readdir(dir); if (!entry) break;
dirname[dirlen] ='\0';
/* append name to current directory */ rb->snprintf(dirname+dirlen, len-dirlen, "/%s", entry->d_name); struct dirinfo info = rb->dir_get_info(dir, entry); if (info.attribute & ATTR_DIRECTORY) { /* remove a subdirectory */ if (!rb->strcmp((char *)entry->d_name, ".") || !rb->strcmp((char *)entry->d_name, "..")) continue; /* skip these */
result = remove_dir(dirname, len); /* recursion */ if (result) break; } else { /* remove a file */ result = rb->remove(dirname); } if (ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD, TIMEOUT_NOBLOCK)) { show_mess("Canceled", NULL); result = -1; break; } } rb->closedir(dir);
if (!result) { /* remove the now empty directory */ dirname[dirlen] = '\0'; /* terminate to original length */
result = rb->rmdir(dirname); show_mess("Removed", dirname); }
return result;}
static int remove_wps(struct remove_setting *setting){ char bmpdir[MAX_PATH]; char *p; rb->strcpy(bmpdir, setting->value); p = rb->strrchr(bmpdir, '.'); if (p) *p = 0; if (!rb->dir_exists(bmpdir)) return 0; return remove_dir(bmpdir, MAX_PATH);}
static int remove_icons(struct remove_setting *setting){ char path[MAX_PATH]; char *p; rb->strcpy(path, setting->value); p = rb->strrchr(path, '.'); rb->strlcpy(p, ".icons", path+MAX_PATH-p);
if (!rb->file_exists(path)) { return 0; } if (rb->remove(path)) { show_mess("Failed", path); return 1; } show_mess("Removed", path); return 0;}
static char font_file[MAX_PATH];
static bool is_deny_file(const char *file){ const char *deny_files[] = { WPS_DEFAULTCFG, RWPS_DEFAULTCFG, font_file, NULL }; const char **p = deny_files; while ( *p ) { if (!rb->strcmp(file, *p)) return true; p++; } return false;}
static void check_whether_used_in_setting(void){ const char *setting_files[] = { rb->global_settings->font_file, rb->global_settings->wps_file, rb->global_settings->sbs_file,#ifdef HAVE_REMOTE_LCD rb->global_settings->rwps_file, rb->global_settings->rsbs_file,#endif#if LCD_DEPTH > 1 rb->global_settings->backdrop_file,#endif rb->global_settings->icon_file, rb->global_settings->viewers_icon_file,#ifdef HAVE_REMOTE_LCD rb->global_settings->remote_icon_file, rb->global_settings->remote_viewers_icon_file,#endif#ifdef HAVE_LCD_COLOR rb->global_settings->colors_file,#endif }; char tempfile[MAX_PATH]; int i; for (i=0; i<NUM_REMOVE_ITEMS; i++) { struct remove_setting *setting = &remove_list[i]; if (setting->value[0]) { set_file_name(tempfile, setting_files[i], setting); if (!rb->strcasecmp(tempfile, setting->value)) setting->used = true; } }}static void check_whether_used_in_file(const char *cfgfile){ char line[MAX_PATH]; char settingfile[MAX_PATH]; char *p; int fd; char *name, *value; int i;
if (!rb->strcasecmp(themefile, cfgfile)) return; fd = rb->open(cfgfile, O_RDONLY); if (fd < 0) return; while (rb->read_line(fd, line, sizeof(line)) > 0) { if (!rb->settings_parseline(line, &name, &value)) continue; /* remove trailing spaces. */ p = value+rb->strlen(value)-1; while (*p == ' ') *p-- = 0; if (*value == 0 || !rb->strcmp(value, "-")) continue; for (i=0; i<NUM_REMOVE_ITEMS; i++) { struct remove_setting *setting = &remove_list[i]; if (!rb->strcmp(name, setting->name)) { if (setting->value[0]) { set_file_name(settingfile, value, setting); if (!rb->strcasecmp(settingfile, setting->value)) setting->used = true; } break; } } } rb->close(fd);}static void check_whether_used(void){ char cfgfile[MAX_PATH]; DIR *dir;
check_whether_used_in_setting(); /* mark font files come from rockbox-font.zip as used and don't remove * them automatically as themes may depend on those fonts. */ if (remove_list[REMOVE_FONT].option == REMOVE_IF_NOT_USED) check_whether_used_in_file(RB_FONTS_CONFIG);
dir = rb->opendir(THEME_DIR); if (!dir) return; /* open error */
while (true) { struct dirent* entry; char *p; int i; /* walk through the directory content */ entry = rb->readdir(dir); if (!entry) break; p = rb->strrchr(entry->d_name, '.'); if (!p || rb->strcmp(p, ".cfg")) continue;
rb->snprintf(cfgfile, MAX_PATH, "%s/%s", THEME_DIR, entry->d_name); check_whether_used_in_file(cfgfile); /* break the loop if all files need to be checked in the theme * turned out to be used. */ for (i = 0; i < NUM_REMOVE_ITEMS; i++) { struct remove_setting *setting = &remove_list[i]; if (setting->option == REMOVE_IF_NOT_USED) { if (setting->value[0] && !setting->used) break; } } if (i == NUM_REMOVE_ITEMS) break; } rb->closedir(dir);}
static int remove_file(struct remove_setting *setting){ if (!rb->file_exists(setting->value)) { show_mess("Doesn't exist", setting->value); return 0; } if (is_deny_file(setting->value)) { show_mess("Denied", setting->value); return 0; } switch (setting->option) { case ALWAYS_REMOVE: break; case NEVER_REMOVE: show_mess("Skipped", setting->value); return 0; break; case REMOVE_IF_NOT_USED: if (setting->used) { show_mess("Used", setting->value); return 0; } break; case ASK_FOR_REMOVAL: default: { const char *message_lines[] = { "Delete?", setting->value }; const struct text_message text_message = { message_lines, 2 }; if (rb->gui_syncyesno_run(&text_message, NULL, NULL) != YESNO_YES) { show_mess("Skipped", setting->value); return 0; } } break; } if (rb->remove(setting->value)) { show_mess("Failed", setting->value); return -1; } if (setting->func && setting->func(setting)) return -1; show_mess("Removed", setting->value); return 1;}static int remove_theme(void){ static char line[MAX_PATH]; int fd; int i, num_removed = 0; char *name, *value; bool needs_to_check_whether_used = false;
/* initialize for safe */ for (i=0; i<NUM_REMOVE_ITEMS; i++) remove_list[i].value[0] = 0;
/* load settings */ fd = rb->open(themefile, O_RDONLY); if (fd < 0) return fd; while (rb->read_line(fd, line, sizeof(line)) > 0) { if (!rb->settings_parseline(line, &name, &value)) continue; /* remove trailing spaces. */ char *p = value+rb->strlen(value)-1; while (*p == ' ') *p-- = 0; if (*value == 0 || !rb->strcmp(value, "-")) continue; for (i=0; i<NUM_REMOVE_ITEMS; i++) { struct remove_setting *setting = &remove_list[i]; if (!rb->strcmp(name, setting->name)) { set_file_name(setting->value, value, setting); if(setting->option == REMOVE_IF_NOT_USED) needs_to_check_whether_used = true; break; } } } rb->close(fd);
if(needs_to_check_whether_used) check_whether_used();
/* now remove file assosiated to the theme. */ for (i=0; i<NUM_REMOVE_ITEMS; i++) { if (remove_list[i].value[0]) { int ret = remove_file(&remove_list[i]); if (ret < 0) return ret; num_removed += ret; } }
/* remove the setting file iff it is in theme directory to protect * aginst accidental removal of non theme cfg file. if the file is * not in the theme directory, the file may not be a theme cfg file. */ if (rb->strncasecmp(themefile, THEME_DIR "/", sizeof(THEME_DIR "/")-1)) { show_mess("Skipped", themefile); } else if (rb->remove(themefile)) { show_mess("Failed", themefile); return -1; } else { show_mess("Removed", themefile); rb->reload_directory(); num_removed++; } return num_removed;}
static bool option_changed = false;static bool option_menu(void){ MENUITEM_STRINGLIST(option_menu, "Remove Options", NULL, /* same order as remove_list */ "Font", "WPS", "Statusbar Skin",#ifdef HAVE_REMOTE_LCD "Remote WPS", "Remote Statusbar Skin",#endif#if LCD_DEPTH > 1 "Backdrop",#endif "Iconset", "Viewers Iconset",#ifdef HAVE_REMOTE_LCD "Remote Iconset", "Remote Viewers Iconset",#endif#ifdef HAVE_LCD_COLOR "Filetype Colours",#endif "Create Log File"); struct opt_items remove_names[] = { {"Always Remove", -1}, {"Never Remove", -1}, {"Remove if not Used", -1}, {"Ask for Removal", -1}, }; int selected = 0, result;
while (1) { result = rb->do_menu(&option_menu, &selected, NULL, false); if (result >= 0 && result < NUM_REMOVE_ITEMS) { struct remove_setting *setting = &remove_list[result]; int prev_option = setting->option; if (rb->set_option(option_menu_[result], &setting->option, RB_INT, remove_names, NUM_REMOVE_OPTION, NULL)) return true; if (prev_option != setting->option) option_changed = true; } else if (result == NUM_REMOVE_ITEMS) { bool prev_value = create_log; if(rb->set_bool("Create Log File", &create_log)) return true; if (prev_value != create_log) option_changed = true; } else if (result == MENU_ATTACHED_USB) return true; else return false; }
return false;}
enum plugin_status plugin_start(const void* parameter){ static char title[64]; char *p; MENUITEM_STRINGLIST(menu, title, NULL, "Remove Theme", "Remove Options", "Quit"); int selected = 0, ret; bool exit = false;
if (!parameter) return PLUGIN_ERROR;
rb->snprintf(title, sizeof(title), "Remove %s", rb->strrchr(parameter, '/')+1); if((p = rb->strrchr(title, '.'))) *p = 0;
rb->snprintf(font_file, MAX_PATH, FONT_DIR "/%s.fnt", rb->global_settings->font_file); rb->strlcpy(themefile, parameter, MAX_PATH); if (!rb->file_exists(themefile)) { rb->splash(HZ, "File open error!"); return PLUGIN_ERROR; } configfile_load(CONFIG_FILENAME, config, nb_config, 0); while (!exit) { switch (rb->do_menu(&menu, &selected, NULL, false)) { case 0: if(create_log) { log_fd = rb->open(LOG_FILENAME, O_WRONLY|O_CREAT|O_APPEND, 0666); if(log_fd >= 0) rb->fdprintf(log_fd, "---- %s ----\n", title); else show_mess("Couldn't open log file.", NULL); } ret = remove_theme(); p = (ret >= 0? "Successfully removed!": "Remove failure"); show_mess(p, NULL); if(log_fd >= 0) { rb->fdprintf(log_fd, "----------------\n"); rb->close(log_fd); log_fd = -1; } rb->lcd_clear_display(); rb->lcd_update(); rb->splashf(0, "%s %s", p, "Press any key to exit."); rb->button_clear_queue(); rb->button_get(true); exit = true; break; case 1: if (option_menu()) return PLUGIN_USB_CONNECTED; break; case 2: exit = true; break; case MENU_ATTACHED_USB: return PLUGIN_USB_CONNECTED; break; default: break; } } if(option_changed) configfile_save(CONFIG_FILENAME, config, nb_config, 0); return PLUGIN_OK;}