1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 #include "lib/configfile.h"
25 /* taken from apps/gui/wps_parser.c */
26 #define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps"
27 #define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps"
29 #define CONFIG_FILENAME "theme_remove.cfg"
30 #define LOG_FILENAME "/theme_remove_log.txt"
31 #define RB_FONTS_CONFIG VIEWERS_DIR "/rockbox-fonts.config"
41 struct remove_setting
{
43 const char *prefix
, *suffix
;
46 int (*func
)(struct remove_setting
*);
50 static int remove_wps(struct remove_setting
*);
51 #ifdef HAVE_LCD_BITMAP
52 static int remove_icons(struct remove_setting
*setting
);
55 enum remove_settings
{
56 #ifdef HAVE_LCD_BITMAP
60 #ifdef HAVE_LCD_BITMAP
63 #ifdef HAVE_REMOTE_LCD
70 #ifdef HAVE_LCD_BITMAP
74 #ifdef HAVE_REMOTE_LCD
84 static bool create_log
= true;
85 static struct remove_setting remove_list
[NUM_REMOVE_ITEMS
] = {
86 #ifdef HAVE_LCD_BITMAP
87 [REMOVE_FONT
] = { "font", FONT_DIR
"/", ".fnt", "",
88 ASK_FOR_REMOVAL
, NULL
, false },
90 [REMOVE_WPS
] = { "wps", WPS_DIR
"/", ".wps", "",
91 REMOVE_IF_NOT_USED
, remove_wps
, false },
92 #ifdef HAVE_LCD_BITMAP
93 [REMOVE_SBS
] = { "sbs", SBS_DIR
"/", ".sbs", "",
94 REMOVE_IF_NOT_USED
, remove_wps
, false },
96 #ifdef HAVE_REMOTE_LCD
97 [REMOVE_RWPS
] = { "rwps", WPS_DIR
"/", ".rwps", "",
98 REMOVE_IF_NOT_USED
, remove_wps
, false },
99 [REMOVE_RSBS
] = { "rsbs", SBS_DIR
"/", ".rsbs", "",
100 REMOVE_IF_NOT_USED
, remove_wps
, false },
103 [REMOVE_BACKDROP
] = { "backdrop", BACKDROP_DIR
"/", ".bmp", "",
104 REMOVE_IF_NOT_USED
, NULL
, false },
106 #ifdef HAVE_LCD_BITMAP
107 [REMOVE_ICON
] = { "iconset", ICON_DIR
"/", ".bmp", "",
108 ASK_FOR_REMOVAL
, NULL
, false },
109 [REMOVE_VICON
] = { "viewers iconset", ICON_DIR
"/", ".bmp", "",
110 ASK_FOR_REMOVAL
, remove_icons
, false },
112 #ifdef HAVE_REMOTE_LCD
113 [REMOVE_RICON
] = { "remote iconset", ICON_DIR
"/", ".bmp", "",
114 ASK_FOR_REMOVAL
, NULL
, false },
115 [REMOVE_RVICON
] = { "remote viewers iconset", ICON_DIR
"/", ".bmp", "",
116 ASK_FOR_REMOVAL
, NULL
, false },
118 #ifdef HAVE_LCD_COLOR
119 [REMOVE_COLOURS
] = { "filetype colours", THEME_DIR
"/", ".colours", "",
120 ASK_FOR_REMOVAL
, NULL
, false },
123 static char *option_names
[NUM_REMOVE_OPTION
] = {
124 "always", "never", "not used", "ask",
126 static struct configdata config
[] = {
127 #ifdef HAVE_LCD_BITMAP
128 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
129 { .int_p
= &remove_list
[REMOVE_FONT
].option
},
130 "remove font", option_names
},
132 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
133 { .int_p
= &remove_list
[REMOVE_WPS
].option
},
134 "remove wps", option_names
},
135 #ifdef HAVE_LCD_BITMAP
136 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
137 { .int_p
= &remove_list
[REMOVE_SBS
].option
},
138 "remove sbs", option_names
},
140 #ifdef HAVE_REMOTE_LCD
141 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
142 { .int_p
= &remove_list
[REMOVE_RWPS
].option
},
143 "remove rwps", option_names
},
144 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
145 { .int_p
= &remove_list
[REMOVE_RSBS
].option
},
146 "remove rsbs", option_names
},
149 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
150 { .int_p
= &remove_list
[REMOVE_BACKDROP
].option
},
151 "remove backdrop", option_names
},
153 #ifdef HAVE_LCD_BITMAP
154 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
155 { .int_p
= &remove_list
[REMOVE_ICON
].option
},
156 "remove iconset", option_names
},
157 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
158 { .int_p
= &remove_list
[REMOVE_VICON
].option
},
159 "remove viconset", option_names
},
161 #ifdef HAVE_REMOTE_LCD
162 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
163 { .int_p
= &remove_list
[REMOVE_RICON
].option
},
164 "remove riconset", option_names
},
165 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
166 { .int_p
= &remove_list
[REMOVE_RVICON
].option
},
167 "remove rviconset", option_names
},
169 #ifdef HAVE_LCD_COLOR
170 { TYPE_INT
, 0, NUM_REMOVE_OPTION
,
171 { .int_p
= &remove_list
[REMOVE_COLOURS
].option
},
172 "remove colours", option_names
},
174 {TYPE_BOOL
, 0, 1, { .bool_p
= &create_log
},
177 static const int nb_config
= sizeof(config
)/sizeof(*config
);
178 static char themefile
[MAX_PATH
];
179 static int log_fd
= -1;
181 static int show_mess(const char *text
, const char *file
)
183 static char buf
[MAX_PATH
*2];
186 rb
->snprintf(buf
, sizeof(buf
), "%s: %s", text
, file
);
188 rb
->snprintf(buf
, sizeof(buf
), "%s", text
);
192 rb
->fdprintf(log_fd
, "%s\n", buf
);
200 /* set full path of file. */
201 static void set_file_name(char *buf
, const char*file
,
202 struct remove_setting
*setting
)
205 if (rb
->strncasecmp(file
, setting
->prefix
, rb
->strlen(setting
->prefix
)))
206 rb
->snprintf(buf
, MAX_PATH
, "%s%s", setting
->prefix
, file
);
208 rb
->strlcpy(buf
, file
, MAX_PATH
);
209 len1
= rb
->strlen(buf
);
210 len2
= rb
->strlen(setting
->suffix
);
211 if (rb
->strcasecmp(buf
+len1
-len2
, setting
->suffix
))
212 rb
->strlcpy(&buf
[len1
], setting
->suffix
, MAX_PATH
-len1
);
215 /* taken from apps/onplay.c */
216 /* helper function to remove a non-empty directory */
217 static int remove_dir(char* dirname
, int len
)
221 int dirlen
= rb
->strlen(dirname
);
223 dir
= rb
->opendir(dirname
);
225 return -1; /* open error */
229 struct dirent
* entry
;
230 /* walk through the directory content */
231 entry
= rb
->readdir(dir
);
235 dirname
[dirlen
] ='\0';
237 /* append name to current directory */
238 rb
->snprintf(dirname
+dirlen
, len
-dirlen
, "/%s", entry
->d_name
);
239 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
240 if (info
.attribute
& ATTR_DIRECTORY
)
242 /* remove a subdirectory */
243 if (!rb
->strcmp((char *)entry
->d_name
, ".") ||
244 !rb
->strcmp((char *)entry
->d_name
, ".."))
245 continue; /* skip these */
247 result
= remove_dir(dirname
, len
); /* recursion */
254 result
= rb
->remove(dirname
);
256 if (ACTION_STD_CANCEL
== rb
->get_action(CONTEXT_STD
, TIMEOUT_NOBLOCK
))
258 show_mess("Canceled", NULL
);
266 { /* remove the now empty directory */
267 dirname
[dirlen
] = '\0'; /* terminate to original length */
269 result
= rb
->rmdir(dirname
);
270 show_mess("Removed", dirname
);
276 static int remove_wps(struct remove_setting
*setting
)
278 char bmpdir
[MAX_PATH
];
280 rb
->strcpy(bmpdir
, setting
->value
);
281 p
= rb
->strrchr(bmpdir
, '.');
283 if (!rb
->dir_exists(bmpdir
))
285 return remove_dir(bmpdir
, MAX_PATH
);
288 #ifdef HAVE_LCD_BITMAP
289 static int remove_icons(struct remove_setting
*setting
)
293 rb
->strcpy(path
, setting
->value
);
294 p
= rb
->strrchr(path
, '.');
295 rb
->strlcpy(p
, ".icons", path
+MAX_PATH
-p
);
297 if (!rb
->file_exists(path
))
301 if (rb
->remove(path
))
303 show_mess("Failed", path
);
306 show_mess("Removed", path
);
311 #ifdef HAVE_LCD_BITMAP
312 static char font_file
[MAX_PATH
];
314 static bool is_deny_file(const char *file
)
316 const char *deny_files
[] = {
319 #ifdef HAVE_LCD_BITMAP
324 const char **p
= deny_files
;
327 if (!rb
->strcmp(file
, *p
))
334 static void check_whether_used_in_setting(void)
336 const char *setting_files
[] = {
337 #ifdef HAVE_LCD_BITMAP
338 rb
->global_settings
->font_file
,
340 rb
->global_settings
->wps_file
,
341 #ifdef HAVE_LCD_BITMAP
342 rb
->global_settings
->sbs_file
,
344 #ifdef HAVE_REMOTE_LCD
345 rb
->global_settings
->rwps_file
,
346 rb
->global_settings
->rsbs_file
,
349 rb
->global_settings
->backdrop_file
,
351 #ifdef HAVE_LCD_BITMAP
352 rb
->global_settings
->icon_file
,
353 rb
->global_settings
->viewers_icon_file
,
355 #ifdef HAVE_REMOTE_LCD
356 rb
->global_settings
->remote_icon_file
,
357 rb
->global_settings
->remote_viewers_icon_file
,
359 #ifdef HAVE_LCD_COLOR
360 rb
->global_settings
->colors_file
,
363 char tempfile
[MAX_PATH
];
365 for (i
=0; i
<NUM_REMOVE_ITEMS
; i
++)
367 struct remove_setting
*setting
= &remove_list
[i
];
368 if (setting
->value
[0])
370 set_file_name(tempfile
, setting_files
[i
], setting
);
371 if (!rb
->strcasecmp(tempfile
, setting
->value
))
372 setting
->used
= true;
376 static void check_whether_used_in_file(const char *cfgfile
)
379 char settingfile
[MAX_PATH
];
385 if (!rb
->strcasecmp(themefile
, cfgfile
))
387 fd
= rb
->open(cfgfile
, O_RDONLY
);
390 while (rb
->read_line(fd
, line
, sizeof(line
)) > 0)
392 if (!rb
->settings_parseline(line
, &name
, &value
))
394 /* remove trailing spaces. */
395 p
= value
+rb
->strlen(value
)-1;
396 while (*p
== ' ') *p
-- = 0;
397 if (*value
== 0 || !rb
->strcmp(value
, "-"))
399 for (i
=0; i
<NUM_REMOVE_ITEMS
; i
++)
401 struct remove_setting
*setting
= &remove_list
[i
];
402 if (!rb
->strcmp(name
, setting
->name
))
404 if (setting
->value
[0])
406 set_file_name(settingfile
, value
, setting
);
407 if (!rb
->strcasecmp(settingfile
, setting
->value
))
408 setting
->used
= true;
416 static void check_whether_used(void)
418 char cfgfile
[MAX_PATH
];
421 check_whether_used_in_setting();
422 #ifdef HAVE_LCD_BITMAP
423 /* mark font files come from rockbox-font.zip as used and don't remove
424 * them automatically as themes may depend on those fonts. */
425 if (remove_list
[REMOVE_FONT
].option
== REMOVE_IF_NOT_USED
)
426 check_whether_used_in_file(RB_FONTS_CONFIG
);
429 dir
= rb
->opendir(THEME_DIR
);
431 return; /* open error */
435 struct dirent
* entry
;
438 /* walk through the directory content */
439 entry
= rb
->readdir(dir
);
442 p
= rb
->strrchr(entry
->d_name
, '.');
443 if (!p
|| rb
->strcmp(p
, ".cfg"))
446 rb
->snprintf(cfgfile
, MAX_PATH
, "%s/%s", THEME_DIR
, entry
->d_name
);
447 check_whether_used_in_file(cfgfile
);
448 /* break the loop if all files need to be checked in the theme
449 * turned out to be used. */
450 for (i
= 0; i
< NUM_REMOVE_ITEMS
; i
++)
452 struct remove_setting
*setting
= &remove_list
[i
];
453 if (setting
->option
== REMOVE_IF_NOT_USED
)
455 if (setting
->value
[0] && !setting
->used
)
459 if (i
== NUM_REMOVE_ITEMS
)
465 static int remove_file(struct remove_setting
*setting
)
467 if (!rb
->file_exists(setting
->value
))
469 show_mess("Doesn't exist", setting
->value
);
472 if (is_deny_file(setting
->value
))
474 show_mess("Denied", setting
->value
);
477 switch (setting
->option
)
482 show_mess("Skipped", setting
->value
);
485 case REMOVE_IF_NOT_USED
:
488 show_mess("Used", setting
->value
);
492 case ASK_FOR_REMOVAL
:
495 const char *message_lines
[] = { "Delete?", setting
->value
};
496 const struct text_message text_message
= { message_lines
, 2 };
497 if (rb
->gui_syncyesno_run(&text_message
, NULL
, NULL
) != YESNO_YES
)
499 show_mess("Skipped", setting
->value
);
505 if (rb
->remove(setting
->value
))
507 show_mess("Failed", setting
->value
);
510 if (setting
->func
&& setting
->func(setting
))
512 show_mess("Removed", setting
->value
);
515 static int remove_theme(void)
517 static char line
[MAX_PATH
];
519 int i
, num_removed
= 0;
521 bool needs_to_check_whether_used
= false;
523 /* initialize for safe */
524 for (i
=0; i
<NUM_REMOVE_ITEMS
; i
++)
525 remove_list
[i
].value
[0] = 0;
528 fd
= rb
->open(themefile
, O_RDONLY
);
529 if (fd
< 0) return fd
;
530 while (rb
->read_line(fd
, line
, sizeof(line
)) > 0)
532 if (!rb
->settings_parseline(line
, &name
, &value
))
534 /* remove trailing spaces. */
535 char *p
= value
+rb
->strlen(value
)-1;
536 while (*p
== ' ') *p
-- = 0;
537 if (*value
== 0 || !rb
->strcmp(value
, "-"))
539 for (i
=0; i
<NUM_REMOVE_ITEMS
; i
++)
541 struct remove_setting
*setting
= &remove_list
[i
];
542 if (!rb
->strcmp(name
, setting
->name
))
544 set_file_name(setting
->value
, value
, setting
);
545 if(setting
->option
== REMOVE_IF_NOT_USED
)
546 needs_to_check_whether_used
= true;
553 if(needs_to_check_whether_used
)
554 check_whether_used();
556 /* now remove file assosiated to the theme. */
557 for (i
=0; i
<NUM_REMOVE_ITEMS
; i
++)
559 if (remove_list
[i
].value
[0])
561 int ret
= remove_file(&remove_list
[i
]);
568 /* remove the setting file iff it is in theme directory to protect
569 * aginst accidental removal of non theme cfg file. if the file is
570 * not in the theme directory, the file may not be a theme cfg file. */
571 if (rb
->strncasecmp(themefile
, THEME_DIR
"/", sizeof(THEME_DIR
"/")-1))
573 show_mess("Skipped", themefile
);
575 else if (rb
->remove(themefile
))
577 show_mess("Failed", themefile
);
582 show_mess("Removed", themefile
);
583 rb
->reload_directory();
589 static bool option_changed
= false;
590 static bool option_menu(void)
592 MENUITEM_STRINGLIST(option_menu
, "Remove Options", NULL
,
593 /* same order as remove_list */
594 #ifdef HAVE_LCD_BITMAP
598 #ifdef HAVE_LCD_BITMAP
601 #ifdef HAVE_REMOTE_LCD
603 "Remote Statusbar Skin",
608 #ifdef HAVE_LCD_BITMAP
609 "Iconset", "Viewers Iconset",
611 #ifdef HAVE_REMOTE_LCD
612 "Remote Iconset", "Remote Viewers Iconset",
614 #ifdef HAVE_LCD_COLOR
618 struct opt_items remove_names
[] = {
619 {"Always Remove", -1}, {"Never Remove", -1},
620 {"Remove if not Used", -1}, {"Ask for Removal", -1},
622 int selected
= 0, result
;
626 result
= rb
->do_menu(&option_menu
, &selected
, NULL
, false);
627 if (result
>= 0 && result
< NUM_REMOVE_ITEMS
)
629 struct remove_setting
*setting
= &remove_list
[result
];
630 int prev_option
= setting
->option
;
631 if (rb
->set_option(option_menu_
[result
], &setting
->option
, INT
,
632 remove_names
, NUM_REMOVE_OPTION
, NULL
))
634 if (prev_option
!= setting
->option
)
635 option_changed
= true;
637 else if (result
== NUM_REMOVE_ITEMS
)
639 bool prev_value
= create_log
;
640 if(rb
->set_bool("Create Log File", &create_log
))
642 if (prev_value
!= create_log
)
643 option_changed
= true;
645 else if (result
== MENU_ATTACHED_USB
)
654 enum plugin_status
plugin_start(const void* parameter
)
656 static char title
[64];
658 MENUITEM_STRINGLIST(menu
, title
, NULL
,
659 "Remove Theme", "Remove Options",
661 int selected
= 0, ret
;
667 rb
->snprintf(title
, sizeof(title
), "Remove %s",
668 rb
->strrchr(parameter
, '/')+1);
669 if((p
= rb
->strrchr(title
, '.')))
672 #ifdef HAVE_LCD_BITMAP
673 rb
->snprintf(font_file
, MAX_PATH
, FONT_DIR
"/%s.fnt",
674 rb
->global_settings
->font_file
);
676 rb
->strlcpy(themefile
, parameter
, MAX_PATH
);
677 if (!rb
->file_exists(themefile
))
679 rb
->splash(HZ
, "File open error!");
682 configfile_load(CONFIG_FILENAME
, config
, nb_config
, 0);
685 switch (rb
->do_menu(&menu
, &selected
, NULL
, false))
690 log_fd
= rb
->open(LOG_FILENAME
, O_WRONLY
|O_CREAT
|O_APPEND
, 0666);
692 rb
->fdprintf(log_fd
, "---- %s ----\n", title
);
694 show_mess("Couldn't open log file.", NULL
);
696 ret
= remove_theme();
697 p
= (ret
>= 0? "Successfully removed!": "Remove failure");
701 rb
->fdprintf(log_fd
, "----------------\n");
705 rb
->lcd_clear_display();
707 rb
->splashf(0, "%s %s", p
, "Press any key to exit.");
708 rb
->button_clear_queue();
709 rb
->button_get(true);
714 return PLUGIN_USB_CONNECTED
;
719 case MENU_ATTACHED_USB
:
720 return PLUGIN_USB_CONNECTED
;
727 configfile_save(CONFIG_FILENAME
, config
, nb_config
, 0);