summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <wilgus.william@gmail.com>2021-11-11 00:05:29 -0500
committerWilliam Wilgus <wilgus.william@gmail.com>2021-11-11 00:28:59 -0500
commit30a23fdd6de8fb46e7b1349126a9ae6921cf7555 (patch)
tree78c1103d3a6f0285cc9555a521fe45d20831379c
parentcf009b4cbb1eec083ab17ce370df090979eaf68e (diff)
downloadrockbox-30a23fdd6de8fb46e7b1349126a9ae6921cf7555.tar.gz
rockbox-30a23fdd6de8fb46e7b1349126a9ae6921cf7555.zip
folder_select.c move to plugin as db_folder_select
handles the folder selection for autoresume paths and database paths folder_select uses the pluginbuf to build the directory tree hopefully having it as a plugin will make it stop corrupting TSR plugins like battery_bench and announce_status I left the original include and source in the gui directory for now there are currently no other users.. Change-Id: If40ccb5a2bec4286a0616c10dfa7e1479a592808
-rw-r--r--apps/menus/settings_menu.c9
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h1
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SOURCES3
-rw-r--r--apps/plugins/db_folder_select.c652
6 files changed, 662 insertions, 5 deletions
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index a5e747651a..94b697aada 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -48,7 +48,6 @@
48#ifdef HAVE_DIRCACHE 48#ifdef HAVE_DIRCACHE
49#include "dircache.h" 49#include "dircache.h"
50#endif 50#endif
51#include "folder_select.h"
52#ifndef HAS_BUTTON_HOLD 51#ifndef HAS_BUTTON_HOLD
53#include "mask_select.h" 52#include "mask_select.h"
54#endif 53#endif
@@ -56,6 +55,7 @@
56#include "governor-ibasso.h" 55#include "governor-ibasso.h"
57#include "usb-ibasso.h" 56#include "usb-ibasso.h"
58#endif 57#endif
58#include "plugin.h"
59 59
60#ifndef HAS_BUTTON_HOLD 60#ifndef HAS_BUTTON_HOLD
61static int selectivesoftlock_callback(int action, 61static int selectivesoftlock_callback(int action,
@@ -133,8 +133,7 @@ static void tagcache_update_with_splash(void)
133 133
134static int dirs_to_scan(void) 134static int dirs_to_scan(void)
135{ 135{
136 if (folder_select(global_settings.tagcache_scan_paths, 136 if(plugin_load(VIEWERS_DIR"/db_folder_select.rock", NULL) > PLUGIN_OK)
137 sizeof(global_settings.tagcache_scan_paths)))
138 { 137 {
139 static const char *lines[] = {ID2P(LANG_TAGCACHE_BUSY), 138 static const char *lines[] = {ID2P(LANG_TAGCACHE_BUSY),
140 ID2P(LANG_TAGCACHE_FORCE_UPDATE)}; 139 ID2P(LANG_TAGCACHE_FORCE_UPDATE)};
@@ -650,8 +649,8 @@ static int autoresume_nexttrack_callback(int action,
650 break; 649 break;
651 case ACTION_EXIT_MENUITEM: 650 case ACTION_EXIT_MENUITEM:
652 if (global_settings.autoresume_automatic == AUTORESUME_NEXTTRACK_CUSTOM 651 if (global_settings.autoresume_automatic == AUTORESUME_NEXTTRACK_CUSTOM
653 && !folder_select(global_settings.autoresume_paths, 652 && plugin_load(VIEWERS_DIR"/db_folder_select.rock",
654 MAX_PATHNAME+1)) 653 str(LANG_AUTORESUME)) == PLUGIN_OK)
655 { 654 {
656 global_settings.autoresume_automatic = oldval; 655 global_settings.autoresume_automatic = oldval;
657 } 656 }
diff --git a/apps/plugin.c b/apps/plugin.c
index c9c3d047d2..a19b3ee226 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -346,6 +346,7 @@ static const struct plugin_api rockbox_api = {
346 gui_syncyesno_run, 346 gui_syncyesno_run,
347 simplelist_info_init, 347 simplelist_info_init,
348 simplelist_show_list, 348 simplelist_show_list,
349 yesno_pop,
349 350
350 /* action handling */ 351 /* action handling */
351 get_custom_action, 352 get_custom_action,
diff --git a/apps/plugin.h b/apps/plugin.h
index 6ca0488e06..e1b7c69f96 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -393,6 +393,7 @@ struct plugin_api {
393 void (*simplelist_info_init)(struct simplelist_info *info, char* title, 393 void (*simplelist_info_init)(struct simplelist_info *info, char* title,
394 int count, void* data); 394 int count, void* data);
395 bool (*simplelist_show_list)(struct simplelist_info *info); 395 bool (*simplelist_show_list)(struct simplelist_info *info);
396 bool (*yesno_pop)(const char* text);
396 397
397 /* action handling */ 398 /* action handling */
398 int (*get_custom_action)(int context,int timeout, 399 int (*get_custom_action)(int context,int timeout,
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 471a32b9e1..5b672fc8ab 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -22,6 +22,7 @@ clock,apps
22codebuster,games 22codebuster,games
23credits,viewers 23credits,viewers
24cube,demos 24cube,demos
25db_folder_select,viewers
25demystify,demos 26demystify,demos
26dice,games 27dice,games
27dict,apps 28dict,apps
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index ec13c17dc9..0635a62d83 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -2,6 +2,9 @@
2#if !defined(SIMULATOR) && (CONFIG_BATTERY_MEASURE != 0) 2#if !defined(SIMULATOR) && (CONFIG_BATTERY_MEASURE != 0)
3battery_bench.c 3battery_bench.c
4#endif 4#endif
5#ifdef HAVE_TAGCACHE
6db_folder_select.c
7#endif
5chessclock.c 8chessclock.c
6credits.c 9credits.c
7cube.c 10cube.c
diff --git a/apps/plugins/db_folder_select.c b/apps/plugins/db_folder_select.c
new file mode 100644
index 0000000000..7f51e520cb
--- /dev/null
+++ b/apps/plugins/db_folder_select.c
@@ -0,0 +1,652 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 Jonathan Gordon
10 * Copyright (C) 2012 Thomas Martitz
11* * Copyright (C) 2021 William Wilgus
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include "plugin.h"
23#ifdef ROCKBOX_HAS_LOGF
24#define logf rb->logf
25#else
26#define logf(...) do { } while(0)
27#endif
28
29/*
30 * Order for changing child states:
31 * 1) expand folder (skip to 3 if empty, skip to 4 if cannot be opened)
32 * 2) collapse and select
33 * 3) unselect (skip to 1)
34 * 4) do nothing
35 */
36
37enum child_state {
38 EXPANDED,
39 SELECTED,
40 COLLAPSED,
41 EACCESS,
42};
43
44struct child {
45 char* name;
46 struct folder *folder;
47 enum child_state state;
48};
49
50struct folder {
51 char *name;
52 struct child *children;
53 struct folder* previous;
54 uint16_t children_count;
55 uint16_t depth;
56};
57
58static char *buffer_front, *buffer_end;
59
60static struct
61{
62 int32_t len; /* keeps count versus maxlen to give buffer full notification */
63 uint32_t val; /* hash of all selected items */
64 char buf[3];/* address used as identifier -- only \0 written to it */
65 char maxlen_exceeded; /*0,1*/
66} hashed;
67
68static inline void get_hash(const char *key, uint32_t *hash, int len)
69{
70 *hash = rb->crc_32(key, len, *hash);
71}
72
73static char* folder_alloc(size_t size)
74{
75 char* retval;
76 /* 32-bit aligned */
77 size = ALIGN_UP(size, 4);
78 if (buffer_front + size > buffer_end)
79 {
80 return NULL;
81 }
82 retval = buffer_front;
83 buffer_front += size;
84 return retval;
85}
86
87static char* folder_alloc_from_end(size_t size)
88{
89 if (buffer_end - size < buffer_front)
90 {
91 return NULL;
92 }
93 buffer_end -= size;
94 return buffer_end;
95}
96#if 0
97/* returns the buffer size required to store the path + \0 */
98static int get_full_pathsz(struct folder *start)
99{
100 int reql = 0;
101 struct folder *next = start;
102 do
103 {
104 reql += rb->strlen(next->name) + 1;
105 } while ((next = next->previous));
106
107 if (start->name[0] != '/') reql--;
108 if (--reql < 0) reql = 0;
109 return reql;
110}
111#endif
112
113static size_t get_full_path(struct folder *start, char *dst, size_t dst_sz)
114{
115 size_t pos = 0;
116 struct folder *prev, *cur = NULL, *next = start;
117 dst[0] = '\0'; /* for rb->strlcat to do its thing */
118 /* First traversal R->L mutate nodes->previous to point at child */
119 while (next->previous != NULL) /* stop at the root */
120 {
121#define PATHMUTATE() \
122 ({ \
123 prev = cur; \
124 cur = next; \
125 next = cur->previous;\
126 cur->previous = prev; \
127 })
128 PATHMUTATE();
129 }
130 /*swap the next and cur nodes to reverse direction */
131 prev = next;
132 next = cur;
133 cur = prev;
134 /* Second traversal L->R mutate nodes->previous to point back at parent
135 * copy strings to buf as they go by */
136 while (next != NULL)
137 {
138 PATHMUTATE();
139 pos = rb->strlcat(dst, cur->name, dst_sz);
140 /* do not append slash to paths starting with slash */
141 if (cur->name[0] != '/')
142 pos = rb->strlcat(dst, "/", dst_sz);
143 }
144 logf("get_full_path: (%d)[%s]", (int)pos, dst);
145 return pos;
146#undef PATHMUTATE
147}
148
149/* support function for rb->qsort() */
150static int compare(const void* p1, const void* p2)
151{
152 struct child *left = (struct child*)p1;
153 struct child *right = (struct child*)p2;
154 return rb->strcasecmp(left->name, right->name);
155}
156
157static struct folder* load_folder(struct folder* parent, char *folder)
158{
159 DIR *dir;
160 char fullpath[MAX_PATH];
161
162 struct dirent *entry;
163 int child_count = 0;
164 char *first_child = NULL;
165 size_t len = 0;
166
167 struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder));
168 if (this == NULL)
169 goto fail;
170
171 if (parent)
172 {
173 len = get_full_path(parent, fullpath, sizeof(fullpath));
174 if (len >= sizeof(fullpath))
175 goto fail;
176 }
177 rb->strlcpy(&fullpath[len], folder, sizeof(fullpath) - len);
178 logf("load_folder: [%s]", fullpath);
179
180 dir = rb->opendir(fullpath);
181 if (dir == NULL)
182 goto fail;
183 this->previous = parent;
184 this->name = folder;
185 this->children = NULL;
186 this->children_count = 0;
187 if (parent)
188 this->depth = parent->depth + 1;
189
190 while ((entry = rb->readdir(dir))) {
191 /* skip anything not a directory */
192 if ((rb->dir_get_info(dir, entry).attribute & ATTR_DIRECTORY) == 0) {
193 continue;
194 }
195 /* skip . and .. */
196 char *dn = entry->d_name;
197 if ((dn[0] == '.') && (dn[1] == '\0' || (dn[1] == '.' && dn[2] == '\0')))
198 continue;
199 /* copy entry name to end of buffer, save pointer */
200 int len = rb->strlen((char *)entry->d_name);
201 char *name = folder_alloc_from_end(len+1); /*for NULL*/
202 if (name == NULL)
203 {
204 rb->closedir(dir);
205 goto fail;
206 }
207 memcpy(name, (char *)entry->d_name, len+1);
208 child_count++;
209 first_child = name;
210 }
211 rb->closedir(dir);
212 /* now put the names in the array */
213 this->children = (struct child*)folder_alloc(sizeof(struct child) * child_count);
214
215 if (this->children == NULL)
216 goto fail;
217
218 while (child_count)
219 {
220 struct child *child = &this->children[this->children_count++];
221 child->name = first_child;
222 child->folder = NULL;
223 child->state = COLLAPSED;
224 while(*first_child++ != '\0'){};/* move to next name entry */
225 child_count--;
226 }
227 rb->qsort(this->children, this->children_count, sizeof(struct child), compare);
228
229 return this;
230fail:
231 return NULL;
232}
233
234struct folder* load_root(void)
235{
236 static struct child root_child;
237 /* reset the root for each call */
238 root_child.name = "/";
239 root_child.folder = NULL;
240 root_child.state = COLLAPSED;
241
242 static struct folder root = {
243 .name = "",
244 .children = &root_child,
245 .children_count = 1,
246 .depth = 0,
247 .previous = NULL,
248 };
249
250 return &root;
251}
252
253static int count_items(struct folder *start)
254{
255 int count = 0;
256 int i;
257
258 for (i=0; i<start->children_count; i++)
259 {
260 struct child *foo = &start->children[i];
261 if (foo->state == EXPANDED)
262 count += count_items(foo->folder);
263 count++;
264 }
265 return count;
266}
267
268static struct child* find_index(struct folder *start, int index, struct folder **parent)
269{
270 int i = 0;
271 *parent = NULL;
272
273 while (i < start->children_count)
274 {
275 struct child *foo = &start->children[i];
276 if (i == index)
277 {
278 *parent = start;
279 return foo;
280 }
281 i++;
282 if (foo->state == EXPANDED)
283 {
284 struct child *bar = find_index(foo->folder, index - i, parent);
285 if (bar)
286 {
287 return bar;
288 }
289 index -= count_items(foo->folder);
290 }
291 }
292 return NULL;
293}
294
295static const char * folder_get_name(int selected_item, void * data,
296 char * buffer, size_t buffer_len)
297{
298 struct folder *root = (struct folder*)data;
299 struct folder *parent;
300 struct child *this = find_index(root, selected_item , &parent);
301
302 char *buf = buffer;
303 if ((int)buffer_len > parent->depth)
304 {
305 int i = parent->depth;
306 while(--i > 0) /* don't indent the parent /folders */
307 *buf++ = '\t';
308 }
309 *buf = '\0';
310 rb->strlcat(buffer, this->name, buffer_len);
311
312 if (this->state == EACCESS)
313 { /* append error message to the entry if unaccessible */
314 size_t len = rb->strlcat(buffer, " ( ", buffer_len);
315 if (buffer_len > len)
316 {
317 rb->snprintf(&buffer[len], buffer_len - len, rb->str(LANG_READ_FAILED), ")");
318 }
319 }
320
321 return buffer;
322}
323
324static enum themable_icons folder_get_icon(int selected_item, void * data)
325{
326 struct folder *root = (struct folder*)data;
327 struct folder *parent;
328 struct child *this = find_index(root, selected_item, &parent);
329
330 switch (this->state)
331 {
332 case SELECTED:
333 return Icon_Cursor;
334 case COLLAPSED:
335 return Icon_Folder;
336 case EXPANDED:
337 return Icon_Submenu;
338 case EACCESS:
339 return Icon_Questionmark;
340 }
341 return Icon_NOICON;
342}
343
344static int child_set_state_expand(struct child *this, struct folder *parent)
345{
346 int newstate = EACCESS;
347 if (this->folder == NULL)
348 this->folder = load_folder(parent, this->name);
349
350 if (this->folder != NULL)
351 {
352 if(this->folder->children_count == 0)
353 newstate = SELECTED;
354 else
355 newstate = EXPANDED;
356 }
357 this->state = newstate;
358 return newstate;
359}
360
361static int folder_action_callback(int action, struct gui_synclist *list)
362{
363 struct folder *root = (struct folder*)list->data;
364 struct folder *parent;
365 struct child *this = find_index(root, list->selected_item, &parent), *child;
366 int i;
367
368 if (action == ACTION_STD_OK)
369 {
370 switch (this->state)
371 {
372 case EXPANDED:
373 this->state = SELECTED;
374 break;
375 case SELECTED:
376 this->state = COLLAPSED;
377 break;
378 case COLLAPSED:
379 child_set_state_expand(this, parent);
380 break;
381 case EACCESS:
382 /* cannot open, do nothing */
383 return action;
384 }
385 action = ACTION_REDRAW;
386 }
387 else if (action == ACTION_STD_CONTEXT)
388 {
389 switch (this->state)
390 {
391 case EXPANDED:
392 for (i = 0; i < this->folder->children_count; i++)
393 {
394 child = &this->folder->children[i];
395 switch (child->state)
396 {
397 case SELECTED:
398 case EXPANDED:
399 child->state = COLLAPSED;
400 break;
401 case COLLAPSED:
402 child->state = SELECTED;
403 break;
404 case EACCESS:
405 break;
406 }
407 }
408 break;
409 case SELECTED:
410 case COLLAPSED:
411 if (child_set_state_expand(this, parent) != EACCESS)
412 {
413 for (i = 0; i < (this->folder->children_count); i++)
414 {
415 child = &this->folder->children[i];
416 child->state = SELECTED;
417 }
418 }
419 break;
420 case EACCESS:
421 /* cannot open, do nothing */
422 return action;
423 }
424 action = ACTION_REDRAW;
425 }
426 if (action == ACTION_REDRAW)
427 list->nb_items = count_items(root);
428 return action;
429}
430
431static struct child* find_from_filename(const char* filename, struct folder *root)
432{
433 if (!root)
434 return NULL;
435 const char *slash = rb->strchr(filename, '/');
436 struct child *this;
437
438 /* filenames beginning with a / are specially treated as the
439 * loop below can't handle them. they can only occur on the first,
440 * and not recursive, calls to this function.*/
441 if (filename[0] == '/') /* in the loop nothing starts with '/' */
442 {
443 logf("find_from_filename [%s]", filename);
444 /* filename begins with /. in this case root must be the
445 * top level folder */
446 this = &root->children[0];
447 if (filename[1] == '\0')
448 { /* filename == "/" */
449 return this;
450 }
451 else /* filename == "/XXX/YYY". cascade down */
452 goto cascade;
453 }
454
455 for (int i = 0; i < root->children_count; i++)
456 {
457 this = &root->children[i];
458 /* when slash == NULL n will be really large but \0 stops the compare */
459 if (rb->strncasecmp(this->name, filename, slash - filename) == 0)
460 {
461 if (slash == NULL)
462 { /* filename == XXX */
463 return this;
464 }
465 else
466 goto cascade;
467 }
468 }
469 return NULL;
470
471cascade:
472 /* filename == XXX/YYY. cascade down */
473 child_set_state_expand(this, root);
474 while (slash[0] == '/') slash++; /* eat slashes */
475 return find_from_filename(slash, this->folder);
476}
477
478static int select_paths(struct folder* root, const char* filenames)
479{
480 /* Takes a list of filenames in a ':' delimited string
481 splits filenames at the ':' character loads each into buffer
482 selects each file in the folder list
483
484 if last item or only item the rest of the string is copied to the buffer
485 *End the last item WITHOUT the ':' character /.rockbox/eqs:/.rockbox/wps\0*
486 */
487 char buf[MAX_PATH];
488 const int buflen = sizeof(buf);
489
490 const char *fnp = filenames;
491 const char *lastfnp = fnp;
492 const char *sstr;
493 off_t len;
494
495 while (fnp)
496 {
497 fnp = rb->strchr(fnp, ':');
498 if (fnp)
499 {
500 len = fnp - lastfnp;
501 fnp++;
502 }
503 else /* no ':' get the rest of the string */
504 len = rb->strlen(lastfnp);
505
506 sstr = lastfnp;
507 lastfnp = fnp;
508 if (len <= 0 || len > buflen)
509 continue;
510 rb->strlcpy(buf, sstr, len + 1);
511 struct child *item = find_from_filename(buf, root);
512 if (item)
513 item->state = SELECTED;
514 }
515
516 return 0;
517}
518
519static void save_folders_r(struct folder *root, char* dst, size_t maxlen, size_t buflen)
520{
521 size_t len;
522 struct folder *curfolder;
523 char* name;
524
525 for (int i = 0; i < root->children_count; i++)
526 {
527 struct child *this = &root->children[i];
528 if (this->state == SELECTED)
529 {
530 if (this->folder == NULL)
531 {
532 curfolder = root;
533 name = this->name;
534 logf("save_folders_r: this->name[%s]", name);
535 }
536 else
537 {
538 curfolder = this->folder->previous;
539 name = this->folder->name;
540 logf("save_folders_r: this->folder->name[%s]", name);
541 }
542
543 len = get_full_path(curfolder, buffer_front, buflen);
544
545 if (len + 2 >= buflen)
546 continue;
547
548 len += rb->snprintf(&buffer_front[len], buflen - len, "%s:", name);
549 logf("save_folders_r: [%s]", buffer_front);
550 if (dst != hashed.buf)
551 {
552 int dlen = rb->strlen(dst);
553 if (dlen + len >= maxlen)
554 continue;
555 rb->strlcpy(&dst[dlen], buffer_front, maxlen - dlen);
556 }
557 else
558 {
559 if (hashed.len + len >= maxlen)
560 {
561 hashed.maxlen_exceeded = 1;
562 continue;
563 }
564 get_hash(buffer_front, &hashed.val, len);
565 hashed.len += len;
566 }
567 }
568 else if (this->state == EXPANDED)
569 save_folders_r(this->folder, dst, maxlen, buflen);
570 }
571}
572
573static uint32_t save_folders(struct folder *root, char* dst, size_t maxlen)
574{
575 hashed.len = 0;
576 hashed.val = 0;
577 hashed.maxlen_exceeded = 0;
578 size_t len = buffer_end - buffer_front;
579 dst[0] = '\0';
580 save_folders_r(root, dst, maxlen, len);
581 len = rb->strlen(dst);
582 /* fix trailing ':' */
583 if (len > 1) dst[len-1] = '\0';
584 /*Notify - user will probably not see save dialog if nothing new got added*/
585 if (hashed.maxlen_exceeded > 0) rb->splash(HZ *2, ID2P(LANG_SHOWDIR_BUFFER_FULL));
586 return hashed.val;
587}
588
589bool folder_select(char * header_text, char* setting, int setting_len)
590{
591 struct folder *root;
592 struct simplelist_info info;
593 size_t buf_size;
594
595 buffer_front = rb->plugin_get_buffer(&buf_size);
596 buffer_end = buffer_front + buf_size;
597 logf("folder_select %d bytes free", (int)(buffer_end - buffer_front));
598 root = load_root();
599
600 logf("folders in: %s", setting);
601 /* Load previous selection(s) */
602 select_paths(root, setting);
603 /* get current hash to check for changes later */
604 uint32_t hash = save_folders(root, hashed.buf, setting_len);
605 rb->simplelist_info_init(&info, header_text,
606 count_items(root), root);
607 info.get_name = folder_get_name;
608 info.action_callback = folder_action_callback;
609 info.get_icon = folder_get_icon;
610 rb->simplelist_show_list(&info);
611 logf("folder_select %d bytes free", (int)(buffer_end - buffer_front));
612 /* done editing. check for changes */
613 if (hash != save_folders(root, hashed.buf, setting_len))
614 { /* prompt for saving changes and commit if yes */
615 if (rb->yesno_pop(ID2P(LANG_SAVE_CHANGES)))
616 {
617 save_folders(root, setting, setting_len);
618 rb->settings_save();
619 logf("folders out: %s", setting);
620 return true;
621 }
622 }
623 return false;
624}
625
626/* plugin entry point */
627enum plugin_status plugin_start(const void* parameter)
628{
629 (void) parameter;
630
631 if(parameter)
632 {
633
634 if (rb->strcmp(parameter, rb->str(LANG_AUTORESUME)) == 0)
635 {
636 if (folder_select(rb->str(LANG_AUTORESUME),
637 rb->global_settings->autoresume_paths,
638 MAX_PATHNAME+1))
639 {
640 return 1;
641 }
642 }
643 }
644 else if (folder_select(rb->str(LANG_SELECT_FOLDER),
645 rb->global_settings->tagcache_scan_paths,
646 sizeof(rb->global_settings->tagcache_scan_paths)))
647 {
648 return 1;
649 }
650
651 return PLUGIN_OK;
652}