summaryrefslogtreecommitdiff
path: root/apps/plugins/shortcuts.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/shortcuts.c')
-rw-r--r--apps/plugins/shortcuts.c550
1 files changed, 0 insertions, 550 deletions
diff --git a/apps/plugins/shortcuts.c b/apps/plugins/shortcuts.c
deleted file mode 100644
index af92bf4634..0000000000
--- a/apps/plugins/shortcuts.c
+++ /dev/null
@@ -1,550 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Bryan Childs
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "plugin.h"
21
22PLUGIN_HEADER
23
24static struct plugin_api* rb;
25
26#define SHORTCUTS_FILENAME "/shortcuts.link"
27#define MAX_SHORTCUTS 50
28
29MEM_FUNCTION_WRAPPERS(rb);
30
31typedef struct sc_file_s
32{
33 int readsize;
34 char* filebuf;
35} sc_file_t;
36
37typedef struct sc_entries_s
38{
39 char shortcut[MAX_PATH+1];
40 int sc_len;
41 struct sc_entries_s* next;
42} sc_entries_t;
43
44enum shortcut_type {
45 SCTYPE_NONE,
46 SCTYPE_FILE,
47 SCTYPE_DIR,
48};
49
50enum sc_list_action_type {
51 SCLA_NONE,
52 SCLA_SELECT,
53 SCLA_DELETE,
54};
55
56void sc_alloc_init(void);
57void* sc_malloc(unsigned int size);
58bool sc_init(void);
59enum sc_list_action_type draw_sc_list(struct gui_synclist gui_sc);
60char* build_sc_list(int selected_item, void* data, char* buffer);
61void delete_sc(int sc_num);
62bool load_sc_file(void);
63bool load_user_sc_file(char* filename);
64bool exists(char* filename);
65enum plugin_status list_sc(void);
66enum plugin_status write_sc_file(char* directory_name,enum shortcut_type st);
67
68char str_dirname[MAX_PATH];
69ssize_t bufleft;
70long mem_ptr;
71long bufsize;
72unsigned char* mallocbuf;
73bool its_a_dir = false;
74bool user_file = false;
75sc_file_t the_file;
76sc_entries_t* shortcuts = 0;
77sc_entries_t* lastentry = 0;
78int total_entries = 0;
79int gselected_item = 0;
80
81void sc_alloc_init(void){
82 mem_ptr=0;
83
84 mallocbuf = rb->plugin_get_buffer(&bufleft);
85 bufsize = (long)bufleft;
86
87 rb->memset(mallocbuf,0,bufsize);
88
89 return;
90}
91
92void* sc_malloc(unsigned int size) {
93 void* x;
94
95 if(mem_ptr + (long)size > bufsize) {
96 rb->splash(HZ*2,"OUT OF MEMORY");
97 return NULL;
98 }
99
100 x=&mallocbuf[mem_ptr];
101 mem_ptr+=(size+3)&~3; /* Keep memory 32-bit aligned */
102
103 return x;
104}
105
106bool exists(char* filename){
107 int fd = 0;
108 /*strip trailing slashes */
109 char* ptr = rb->strrchr((char*)filename, '/') + 1;
110 int dirlen = (ptr - (char*)filename);
111 rb->strncpy(str_dirname, (char*)filename, dirlen);
112 str_dirname[dirlen] = 0;
113
114 fd = rb->open(str_dirname,O_RDONLY);
115 if (!fd) {
116 return false;
117 }
118 rb->close(fd);
119 return true;
120}
121
122bool sc_init(void) {
123 return load_sc_file();
124}
125
126enum sc_list_action_type draw_sc_list(struct gui_synclist gui_sc) {
127 int button;
128
129 rb->gui_synclist_draw(&gui_sc);
130
131 while (true) {
132 /* draw the statusbar, should be done often */
133 rb->gui_syncstatusbar_draw(rb->statusbars, true);
134 /* user input */
135 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
136 if (rb->gui_synclist_do_button(&gui_sc,button,
137 LIST_WRAP_UNLESS_HELD)) {
138 /* automatic handling of user input.
139 * _UNLESS_HELD can be _ON or _OFF also
140 * selection changed, so redraw */
141 continue;
142 }
143 switch (button) { /* process the user input */
144 case ACTION_STD_OK:
145 gselected_item = rb->gui_synclist_get_sel_pos(&gui_sc);
146 return SCLA_SELECT;
147 break;
148 case ACTION_STD_MENU:
149 if(!user_file){
150 gselected_item = rb->gui_synclist_get_sel_pos(&gui_sc);
151 rb->splash(HZ,"Deleting item");
152 return SCLA_DELETE;
153 } else {
154 return SCLA_NONE;
155 }
156 break;
157 case ACTION_STD_CANCEL:
158 return SCLA_NONE;
159 break;
160 }
161 }
162}
163
164char* build_sc_list(int selected_item, void* data, char* buffer) {
165 int i;
166 sc_entries_t* temp_node = (sc_entries_t*)data;
167 char text_buffer[MAX_PATH];
168
169 for (i=0;i<selected_item && temp_node != NULL;i++){
170 temp_node = temp_node->next;
171 }
172 if (temp_node == NULL){
173 return NULL;
174 }
175 rb->snprintf(text_buffer, MAX_PATH, "%s", temp_node->shortcut);
176
177 rb->strcpy(buffer, text_buffer);
178 return buffer;
179}
180
181void delete_sc(int sc_num){
182 /* Note: This function is a nasty hack and I should probably
183 * be shot for doing it this way.*/
184 int i;
185 sc_entries_t* current = shortcuts;
186 sc_entries_t* previous = shortcuts;
187
188 if(total_entries==1){
189 /* This is the only item in the file
190 * so just set the whole shortcuts list
191 * to zero */
192 shortcuts=0;
193 } else {
194 if(sc_num!=0){
195 for (i=0;i<sc_num && current != NULL;i++){
196 /* keep previous pointing at the prior
197 * item in the list */
198 if(previous!=current){
199 previous = current;
200 }
201 current=current->next;
202 }
203 /* current should now be pointing at the item
204 * to be deleted, so update the previous item
205 * to point to whatever current is pointing to
206 * as next item */
207 if(current){
208 previous->next = current->next;
209 }else{
210 previous->next = 0;
211 }
212 }else{
213 shortcuts = shortcuts->next;
214 }
215 }
216 return;
217}
218
219enum plugin_status list_sc(void) {
220 int selected_item = 0;
221 char selected_dir[MAX_PATH];
222 enum sc_list_action_type action = SCLA_NONE;
223 struct gui_synclist gui_sc;
224
225 rb->memset(selected_dir,0,MAX_PATH);
226
227 /* Setup the GUI list object, draw it to the screen,
228 * and then handle the user input to it */
229 rb->gui_synclist_init(&gui_sc,&build_sc_list,shortcuts,false,1);
230 rb->gui_synclist_set_title(&gui_sc,"Shortcuts",NOICON);
231 rb->gui_synclist_set_nb_items(&gui_sc,total_entries);
232 rb->gui_synclist_limit_scroll(&gui_sc,false);
233 rb->gui_synclist_select_item(&gui_sc,0);
234
235 /* Draw the prepared widget to the LCD now */
236 action = draw_sc_list(gui_sc);
237
238 /* which item do we action? */
239 selected_item = gselected_item;
240
241 /* Find out which option the user selected.
242 * Handily, the callback function which is used
243 * to populate the list is equally useful here! */
244 build_sc_list(selected_item,(void*)shortcuts,selected_dir);
245
246 /* perform the following actions if the user "selected"
247 * the item in the list (i.e. they want to go there
248 * in the filebrowser tree */
249 switch(action) {
250 case SCLA_SELECT:
251 /* Check to see if the directory referenced still exists */
252 if(!exists(selected_dir)){
253 rb->splash(HZ*2,"File / Directory no longer exists on disk");
254 return PLUGIN_ERROR;
255 }
256
257 /* Set the browsers dirfilter to the global setting
258 * This is required in case the plugin was launched
259 * from the plugins browser, in which case the
260 * dirfilter is set to only display .rock files */
261 rb->set_dirfilter(rb->global_settings->dirfilter);
262
263 /* Change directory to the entry selected by the user */
264 rb->set_current_file(selected_dir);
265 break;
266 case SCLA_DELETE:
267 delete_sc(selected_item);
268 return write_sc_file(0,SCTYPE_NONE);
269 break;
270 case SCLA_NONE:
271 return PLUGIN_OK;
272 break;
273 }
274 return PLUGIN_OK;
275}
276
277bool load_sc_file(void){
278 int fd = 0;
279 int amountread = 0;
280 char sc_content[MAX_PATH];
281 sc_entries_t* entry = 0;
282
283 fd = rb->open(SHORTCUTS_FILENAME,O_RDONLY);
284 if(fd<0){
285 /* The shortcuts.link file didn't exist on disk
286 * so create an empty one.
287 */
288 fd = rb->creat(SHORTCUTS_FILENAME);
289 if(fd<0){
290 /* For some reason we couldn't create a new shortcuts.link
291 * file, so return an error message and exit
292 */
293 rb->splash(HZ*2,"Couldn't create the shortcuts file");
294 return false;
295 }
296 /* File created, but there's nothing in it
297 * so just exit */
298 rb->close(fd);
299 return true;
300 }
301
302 /* if we get to here, the file already exists, and has been opened
303 * successfully, so we can start reading it
304 */
305 while((amountread=rb->read_line(fd,sc_content,MAX_PATH))){
306 if(!(entry = (sc_entries_t*)sc_malloc(sizeof(sc_entries_t)))){
307 rb->splash(HZ*2,"Couldn't get memory for a new entry");
308 rb->close(fd);
309 return false;
310 }
311 if(shortcuts==NULL) {
312 /* This is the first entry created, so set
313 * shortcuts to point to it
314 */
315 shortcuts=entry;
316 }
317 if(lastentry!=NULL) {
318 /* This isn't the first item in the list
319 * so update the previous item in the list
320 * to point to this new item.
321 */
322 lastentry->next = entry;
323 }
324
325 total_entries++;
326 rb->snprintf(entry->shortcut,amountread,"%s",sc_content);
327 entry->sc_len = amountread-1;
328
329 /* Make sure the 'next' pointer is null */
330 entry->next=0;
331
332 /* Now we can make last look at this entry,
333 * ready for the next one
334 */
335 lastentry = entry;
336 }
337 rb->close(fd);
338 return true;
339}
340
341bool load_user_sc_file(char* filename){
342 int fd = 0;
343 int amountread = 0;
344 char sc_content[MAX_PATH];
345 sc_entries_t* entry = 0;
346
347 /* user has chosen to open a non-default .link file
348 * so overwrite current memory contents */
349 shortcuts = 0;
350 lastentry = 0;
351 total_entries = 0;
352
353 fd = rb->open(filename,O_RDONLY);
354 if(fd<0){
355 /* The shortcuts.link file didn't exist on disk
356 * so create an empty one.
357 */
358 rb->splash(HZ,"Couldn't open %s",filename);
359 return false;
360 }
361
362 while((amountread=rb->read_line(fd,sc_content,MAX_PATH))){
363 if(!(entry = (sc_entries_t*)sc_malloc(sizeof(sc_entries_t)))){
364 rb->splash(HZ*2,"Couldn't get memory for a new entry");
365 rb->close(fd);
366 return false;
367 }
368 if(shortcuts==NULL) {
369 /* This is the first entry created, so set
370 * shortcuts to point to it
371 */
372 shortcuts=entry;
373 }
374 if(lastentry!=NULL) {
375 /* This isn't the first item in the list
376 * so update the previous item in the list
377 * to point to this new item.
378 */
379 lastentry->next = entry;
380 }
381
382 total_entries++;
383 rb->snprintf(entry->shortcut,amountread,"%s",sc_content);
384 entry->sc_len = amountread-1;
385
386 /* Make sure the 'next' pointer is null */
387 entry->next=0;
388
389 /* Now we can make last look at this entry,
390 * ready for the next one
391 */
392 lastentry = entry;
393 }
394 rb->close(fd);
395 return true;
396}
397
398enum plugin_status write_sc_file(char* directory_name, enum shortcut_type st) {
399 int fd;
400 int i;
401 sc_entries_t *temp_node = shortcuts;
402 char text_buffer[MAX_PATH];
403
404 if(total_entries>=MAX_SHORTCUTS) {
405 /* too many entries in the file already
406 * so don't add this one, and give the
407 * user an error */
408 rb->splash(HZ*2,"Shortcuts file is full");
409 return PLUGIN_ERROR;
410 }
411
412 /* ideally, we should just write a new
413 * entry to the file, but I'm going to
414 * be lazy, and just re-write the whole
415 * thing. */
416 fd = rb->open(SHORTCUTS_FILENAME,O_RDWR);
417 if(fd<0){
418 rb->splash(HZ*2,"Error writing to shortcuts file");
419 return PLUGIN_ERROR;
420 }
421
422 /* truncate the current file, since we're writing it
423 * all over again */
424 rb->ftruncate(fd,0);
425
426 /* Check to see that the list is not empty */
427 if(temp_node){
428 for (i=0;i<MAX_SHORTCUTS && temp_node != NULL;i++){
429 rb->snprintf(text_buffer,temp_node->sc_len+2,
430 "%s\n",temp_node->shortcut);
431 rb->write(fd,text_buffer,temp_node->sc_len+1);
432 temp_node = temp_node->next;
433 }
434 }
435 /* Reached the end of the existing entries, so check to
436 * see if we need to add one more for the new entry
437 */
438 if(st!=SCTYPE_NONE){
439 if(st==SCTYPE_FILE) {
440 rb->snprintf(text_buffer,rb->strlen(directory_name)+2, /*+2 is \n and 0x00 */
441 "%s\n",directory_name);
442 rb->write(fd,text_buffer,rb->strlen(directory_name)+1);
443 } else if(st==SCTYPE_DIR){
444 rb->snprintf(text_buffer,rb->strlen(directory_name)+3, /*+3 is /, \n and 0x00 */
445 "%s/\n",directory_name);
446 rb->write(fd,text_buffer,rb->strlen(directory_name)+2);
447 }
448 }
449 rb->close(fd);
450
451 return PLUGIN_OK;
452}
453
454enum plugin_status plugin_start(struct plugin_api* api, void* parameter) {
455 rb = api;
456 bool found = false;
457
458 DIR* dir;
459 struct dirent* entry;
460
461 /* Initialise the plugin buffer */
462 sc_alloc_init();
463
464 if(!sc_init())
465 return PLUGIN_ERROR;
466
467 /* Were we passed a parameter at startup? */
468 if(parameter) {
469 /* determine if it's a file or a directory */
470 char* ptr = rb->strrchr((char*)parameter, '/') + 1;
471 int dirlen = (ptr - (char*)parameter);
472 rb->strncpy(str_dirname, (char*)parameter, dirlen);
473 str_dirname[dirlen] = 0;
474
475 dir = rb->opendir(str_dirname);
476 if (dir) {
477 while(0 != (entry = rb->readdir(dir))) {
478 if(!rb->strcmp(entry->d_name, parameter+dirlen)) {
479 its_a_dir = entry->attribute & ATTR_DIRECTORY ?
480 true : false;
481 found = true;
482 break;
483 }
484 }
485 rb->closedir(dir);
486 }
487 /* now we know if it's a file or a directory
488 * (or something went wrong) */
489
490 if(!found) {
491 /* Something's gone properly pear shaped -
492 * we couldn't even find the entry */
493 rb->splash(HZ*2,"File / Directory not found : %s",
494 (char*)parameter);
495 return PLUGIN_ERROR;
496 }
497
498 if(!its_a_dir) {
499 /* Don't add the shortcuts.link file to itself */
500 if(rb->strcmp((char*)parameter,SHORTCUTS_FILENAME)==0){
501 return list_sc();
502 }
503 /* this section handles user created .link files */
504 if(rb->strcasestr((char*)parameter,".link")){
505 if(!load_user_sc_file((char*)parameter)){
506 return PLUGIN_ERROR;
507 }
508 user_file = true;
509 if(total_entries==1){
510 /* if there's only one entry in the user .link file,
511 * go straight to it without displaying the menu */
512 char selected_dir[MAX_PATH];
513 /* go to entry immediately */
514 build_sc_list(0,(void*)shortcuts,selected_dir);
515
516 /* Check to see if the directory referenced still exists */
517 if(!exists(selected_dir)){
518 rb->splash(HZ*2,"File / Directory no longer exists on disk");
519 return PLUGIN_ERROR;
520 }
521
522 /* Set the browsers dirfilter to the global setting */
523 rb->set_dirfilter(rb->global_settings->dirfilter);
524
525 /* Change directory to the entry selected by the user */
526 rb->set_current_file(selected_dir);
527 return PLUGIN_OK;
528 }else{
529 /* This user created link file has multiple entries in it
530 * so display a menu to choose between them */
531 return list_sc();
532 }
533 } else {
534 /* This isn't a .link file so add it to the shortcuts.link
535 * file as a new entry */
536 return write_sc_file((char*)parameter,SCTYPE_FILE);
537 }
538 }else{
539 /* This is a directory and should be added to
540 * the shortcuts.link file */
541 return write_sc_file((char*)parameter,SCTYPE_DIR);
542 }
543 }
544 else { /* We weren't passed a parameter, so open the
545 * shortcuts file directly */
546 return list_sc();
547 }
548 return PLUGIN_OK;
549}
550