diff options
Diffstat (limited to 'apps/onplay.c')
-rw-r--r-- | apps/onplay.c | 299 |
1 files changed, 293 insertions, 6 deletions
diff --git a/apps/onplay.c b/apps/onplay.c index e057623c1c..62ba0a1005 100644 --- a/apps/onplay.c +++ b/apps/onplay.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #include <errno.h> | ||
19 | #include <stdio.h> | 20 | #include <stdio.h> |
20 | #include <string.h> | 21 | #include <string.h> |
21 | #include <stdlib.h> | 22 | #include <stdlib.h> |
@@ -67,6 +68,9 @@ static int context; | |||
67 | static char* selected_file = NULL; | 68 | static char* selected_file = NULL; |
68 | static int selected_file_attr = 0; | 69 | static int selected_file_attr = 0; |
69 | static int onplay_result = ONPLAY_OK; | 70 | static int onplay_result = ONPLAY_OK; |
71 | static char clipboard_selection[MAX_PATH]; | ||
72 | static int clipboard_selection_attr = 0; | ||
73 | static bool clipboard_is_copy = false; | ||
70 | 74 | ||
71 | /* For playlist options */ | 75 | /* For playlist options */ |
72 | struct playlist_args { | 76 | struct playlist_args { |
@@ -516,6 +520,262 @@ bool create_dir(void) | |||
516 | return true; | 520 | return true; |
517 | } | 521 | } |
518 | 522 | ||
523 | /* Store the current selection in the clipboard */ | ||
524 | static bool clipboard_clip(bool copy) | ||
525 | { | ||
526 | clipboard_selection[0] = 0; | ||
527 | strncpy(clipboard_selection, selected_file, MAX_PATH); | ||
528 | clipboard_selection_attr = selected_file_attr; | ||
529 | clipboard_is_copy = copy; | ||
530 | |||
531 | return true; | ||
532 | } | ||
533 | |||
534 | static bool clipboard_cut(void) | ||
535 | { | ||
536 | return clipboard_clip(false); | ||
537 | } | ||
538 | |||
539 | static bool clipboard_copy(void) | ||
540 | { | ||
541 | return clipboard_clip(true); | ||
542 | } | ||
543 | |||
544 | /* Paste a file to a new directory. Will overwrite always. */ | ||
545 | static bool clipboard_pastefile(const char *src, const char *target, bool copy) | ||
546 | { | ||
547 | int src_fd, target_fd, buffersize, size, bytesread, byteswritten; | ||
548 | char *buffer; | ||
549 | bool result = false; | ||
550 | |||
551 | if (copy) { | ||
552 | /* See if we can get the plugin buffer for the file copy buffer */ | ||
553 | buffer = (char *) plugin_get_buffer(&buffersize); | ||
554 | if (buffer == NULL || buffersize < 512) { | ||
555 | /* Not large enough, try for a disk sector worth of stack instead */ | ||
556 | buffersize = 512; | ||
557 | buffer = (char *) __builtin_alloca(buffersize); | ||
558 | } | ||
559 | |||
560 | if (buffer == NULL) { | ||
561 | return false; | ||
562 | } | ||
563 | |||
564 | buffersize &= ~0x1ff; /* Round buffer size to multiple of sector size */ | ||
565 | |||
566 | src_fd = open(src, O_RDONLY); | ||
567 | |||
568 | if (src_fd >= 0) { | ||
569 | target_fd = creat(target, O_WRONLY); | ||
570 | |||
571 | if (target_fd >= 0) { | ||
572 | result = true; | ||
573 | |||
574 | size = filesize(src_fd); | ||
575 | |||
576 | if (size == -1) { | ||
577 | result = false; | ||
578 | } | ||
579 | |||
580 | while(size > 0) { | ||
581 | bytesread = read(src_fd, buffer, buffersize); | ||
582 | |||
583 | if (bytesread == -1) { | ||
584 | result = false; | ||
585 | break; | ||
586 | } | ||
587 | |||
588 | size -= bytesread; | ||
589 | |||
590 | while(bytesread > 0) { | ||
591 | byteswritten = write(target_fd, buffer, bytesread); | ||
592 | |||
593 | if (byteswritten == -1) { | ||
594 | result = false; | ||
595 | size = 0; | ||
596 | break; | ||
597 | } | ||
598 | |||
599 | bytesread -= byteswritten; | ||
600 | } | ||
601 | } | ||
602 | |||
603 | close(target_fd); | ||
604 | |||
605 | /* Copy failed. Cleanup. */ | ||
606 | if (!result) { | ||
607 | remove(target); | ||
608 | } | ||
609 | } | ||
610 | |||
611 | close(src_fd); | ||
612 | } | ||
613 | } else { | ||
614 | result = rename(src, target) == 0; | ||
615 | #ifdef HAVE_MULTIVOLUME | ||
616 | if (!result) { | ||
617 | if (errno == EXDEV) { | ||
618 | /* Failed because cross volume rename doesn't work. Copy instead */ | ||
619 | result = clipboard_pastefile(src, target, true); | ||
620 | |||
621 | if (result) { | ||
622 | result = remove(src); | ||
623 | } | ||
624 | } | ||
625 | } | ||
626 | #endif | ||
627 | } | ||
628 | |||
629 | return result; | ||
630 | } | ||
631 | |||
632 | /* Paste a directory to a new location. Designed to be called by clipboard_paste */ | ||
633 | static bool clipboard_pastedirectory(char *src, int srclen, char *target, int targetlen, bool copy) | ||
634 | { | ||
635 | DIR *srcdir; | ||
636 | int srcdirlen = strlen(src); | ||
637 | int targetdirlen = strlen(target); | ||
638 | int fd; | ||
639 | bool result = true; | ||
640 | |||
641 | /* Check if the target exists */ | ||
642 | fd = open(target, O_RDONLY); | ||
643 | close(fd); | ||
644 | |||
645 | if (fd < 0) { | ||
646 | if (!copy) { | ||
647 | /* Just move the directory */ | ||
648 | result = rename(src, target) == 0; | ||
649 | |||
650 | #ifdef HAVE_MULTIVOLUME | ||
651 | if (!result && errno == EXDEV) { | ||
652 | /* Try a copy as we're going across devices */ | ||
653 | result = clipboard_pastedirectory(src, srclen, target, targetlen, true); | ||
654 | |||
655 | /* If it worked, remove the source directory */ | ||
656 | if (result) { | ||
657 | remove_dir(src, srclen); | ||
658 | } | ||
659 | } | ||
660 | #endif | ||
661 | return result; | ||
662 | } else { | ||
663 | /* Make a directory to copy things to */ | ||
664 | result = mkdir(target, 0) == 0; | ||
665 | } | ||
666 | } | ||
667 | |||
668 | /* Check if something went wrong already */ | ||
669 | if (!result) { | ||
670 | return result; | ||
671 | } | ||
672 | |||
673 | srcdir = opendir(src); | ||
674 | if (!srcdir) { | ||
675 | return false; | ||
676 | } | ||
677 | |||
678 | /* This loop will exit as soon as there's a problem */ | ||
679 | while(result) | ||
680 | { | ||
681 | struct dirent* entry; | ||
682 | /* walk through the directory content */ | ||
683 | entry = readdir(srcdir); | ||
684 | if (!entry) | ||
685 | break; | ||
686 | |||
687 | /* append name to current directory */ | ||
688 | snprintf(src+srcdirlen, srclen-srcdirlen, "/%s", entry->d_name); | ||
689 | snprintf(target+targetdirlen, targetlen-targetdirlen, "/%s", entry->d_name); | ||
690 | |||
691 | DEBUGF("Copy %s to %s\n", src, target); | ||
692 | |||
693 | if (entry->attribute & ATTR_DIRECTORY) | ||
694 | { /* copy/move a subdirectory */ | ||
695 | if (!strcmp((char *)entry->d_name, ".") || | ||
696 | !strcmp((char *)entry->d_name, "..")) | ||
697 | continue; /* skip these */ | ||
698 | |||
699 | result = clipboard_pastedirectory(src, srclen, target, targetlen, copy); /* recursion */ | ||
700 | } | ||
701 | else | ||
702 | { /* copy/move a file */ | ||
703 | result = clipboard_pastefile(src, target, copy); | ||
704 | } | ||
705 | } | ||
706 | |||
707 | closedir(srcdir); | ||
708 | |||
709 | if (result) { | ||
710 | src[srcdirlen] = '\0'; /* terminate to original length */ | ||
711 | target[targetdirlen] = '\0'; /* terminate to original length */ | ||
712 | } | ||
713 | |||
714 | return result; | ||
715 | } | ||
716 | |||
717 | /* Paste the clipboard to the current directory */ | ||
718 | static bool clipboard_paste(void) | ||
719 | { | ||
720 | char target[MAX_PATH]; | ||
721 | char *cwd, *nameptr; | ||
722 | bool success; | ||
723 | int target_fd; | ||
724 | |||
725 | unsigned char *lines[]={str(LANG_REALLY_OVERWRITE)}; | ||
726 | struct text_message message={(char **)lines, 1}; | ||
727 | |||
728 | /* Get the name of the current directory */ | ||
729 | cwd = getcwd(NULL, 0); | ||
730 | snprintf(target, sizeof target, "%s", cwd[1] ? cwd : ""); | ||
731 | |||
732 | /* Figure out the name of the selection */ | ||
733 | nameptr = strrchr(clipboard_selection, '/'); | ||
734 | |||
735 | /* Paste the name on to the current directory to give us our final target */ | ||
736 | strcat(target, nameptr); | ||
737 | |||
738 | /* Check if we're going to overwrite */ | ||
739 | target_fd = open(target, O_RDONLY); | ||
740 | close(target_fd); | ||
741 | |||
742 | /* If the target existed but they choose not to overwite, exit */ | ||
743 | if (target_fd >= 0 && | ||
744 | (gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO)) { | ||
745 | return false; | ||
746 | } | ||
747 | |||
748 | /* Now figure out what we're doing */ | ||
749 | if (clipboard_selection_attr & ATTR_DIRECTORY) { | ||
750 | /* Recursion. Set up external stack */ | ||
751 | char srcpath[MAX_PATH]; | ||
752 | char targetpath[MAX_PATH]; | ||
753 | |||
754 | strncpy(srcpath, clipboard_selection, sizeof srcpath); | ||
755 | strncpy(targetpath, target, sizeof targetpath); | ||
756 | |||
757 | success = clipboard_pastedirectory(srcpath, sizeof(srcpath), target, sizeof(targetpath), clipboard_is_copy); | ||
758 | } else { | ||
759 | success = clipboard_pastefile(clipboard_selection, target, clipboard_is_copy); | ||
760 | } | ||
761 | |||
762 | /* Did it work? */ | ||
763 | if (success) { | ||
764 | /* Reset everything */ | ||
765 | clipboard_selection[0] = 0; | ||
766 | clipboard_selection_attr = 0; | ||
767 | clipboard_is_copy = false; | ||
768 | |||
769 | /* Force reload of the current directory */ | ||
770 | onplay_result = ONPLAY_RELOAD_DIR; | ||
771 | } else { | ||
772 | gui_syncsplash(HZ, true, (unsigned char *)"%s %s", | ||
773 | str(LANG_PASTE), str(LANG_FAILED)); | ||
774 | } | ||
775 | |||
776 | return true; | ||
777 | } | ||
778 | |||
519 | static bool exit_to_main; | 779 | static bool exit_to_main; |
520 | 780 | ||
521 | /* catch MENU_EXIT_MENU within context menu to call the main menu afterwards */ | 781 | /* catch MENU_EXIT_MENU within context menu to call the main menu afterwards */ |
@@ -536,9 +796,9 @@ static int onplay_callback(int key, int menu) | |||
536 | int onplay(char* file, int attr, int from) | 796 | int onplay(char* file, int attr, int from) |
537 | { | 797 | { |
538 | #if CONFIG_CODEC == SWCODEC | 798 | #if CONFIG_CODEC == SWCODEC |
539 | struct menu_item items[10]; /* increase this if you add entries! */ | 799 | struct menu_item items[13]; /* increase this if you add entries! */ |
540 | #else | 800 | #else |
541 | struct menu_item items[8]; | 801 | struct menu_item items[11]; |
542 | #endif | 802 | #endif |
543 | int m, i=0, result; | 803 | int m, i=0, result; |
544 | #ifdef HAVE_LCD_COLOR | 804 | #ifdef HAVE_LCD_COLOR |
@@ -557,7 +817,7 @@ int onplay(char* file, int attr, int from) | |||
557 | items[i].function = sound_menu; | 817 | items[i].function = sound_menu; |
558 | i++; | 818 | i++; |
559 | } | 819 | } |
560 | 820 | ||
561 | if (context == CONTEXT_WPS || | 821 | if (context == CONTEXT_WPS || |
562 | context == CONTEXT_TREE || | 822 | context == CONTEXT_TREE || |
563 | ((context == CONTEXT_ID3DB) && | 823 | ((context == CONTEXT_ID3DB) && |
@@ -582,7 +842,8 @@ int onplay(char* file, int attr, int from) | |||
582 | items[i].desc = ID2P(LANG_MENU_SHOW_ID3_INFO); | 842 | items[i].desc = ID2P(LANG_MENU_SHOW_ID3_INFO); |
583 | items[i].function = browse_id3; | 843 | items[i].function = browse_id3; |
584 | i++; | 844 | i++; |
585 | if(rundb_initialized) { | 845 | if(rundb_initialized) |
846 | { | ||
586 | items[i].desc = ID2P(LANG_MENU_SET_RATING); | 847 | items[i].desc = ID2P(LANG_MENU_SET_RATING); |
587 | items[i].function = set_rating; | 848 | items[i].function = set_rating; |
588 | i++; | 849 | i++; |
@@ -598,6 +859,21 @@ int onplay(char* file, int attr, int from) | |||
598 | items[i].desc = ID2P(LANG_RENAME); | 859 | items[i].desc = ID2P(LANG_RENAME); |
599 | items[i].function = rename_file; | 860 | items[i].function = rename_file; |
600 | i++; | 861 | i++; |
862 | |||
863 | items[i].desc = ID2P(LANG_CUT); | ||
864 | items[i].function = clipboard_cut; | ||
865 | i++; | ||
866 | |||
867 | items[i].desc = ID2P(LANG_COPY); | ||
868 | items[i].function = clipboard_copy; | ||
869 | i++; | ||
870 | |||
871 | if (clipboard_selection[0] != 0) /* Something in the clipboard? */ | ||
872 | { | ||
873 | items[i].desc = ID2P(LANG_PASTE); | ||
874 | items[i].function = clipboard_paste; | ||
875 | i++; | ||
876 | } | ||
601 | } | 877 | } |
602 | 878 | ||
603 | if (!(attr & ATTR_DIRECTORY) && context == CONTEXT_TREE) | 879 | if (!(attr & ATTR_DIRECTORY) && context == CONTEXT_TREE) |
@@ -608,8 +884,10 @@ int onplay(char* file, int attr, int from) | |||
608 | 884 | ||
609 | #ifdef HAVE_LCD_COLOR | 885 | #ifdef HAVE_LCD_COLOR |
610 | suffix = strrchr(file, '.'); | 886 | suffix = strrchr(file, '.'); |
611 | if (suffix) { | 887 | if (suffix) |
612 | if (strcasecmp(suffix, ".bmp") == 0) { | 888 | { |
889 | if (strcasecmp(suffix, ".bmp") == 0) | ||
890 | { | ||
613 | items[i].desc = ID2P(LANG_SET_AS_BACKDROP); | 891 | items[i].desc = ID2P(LANG_SET_AS_BACKDROP); |
614 | items[i].function = set_backdrop; | 892 | items[i].function = set_backdrop; |
615 | i++; | 893 | i++; |
@@ -635,6 +913,15 @@ int onplay(char* file, int attr, int from) | |||
635 | i++; | 913 | i++; |
636 | } | 914 | } |
637 | } | 915 | } |
916 | else | ||
917 | { | ||
918 | if (strlen(clipboard_selection) != 0) | ||
919 | { | ||
920 | items[i].desc = ID2P(LANG_PASTE); | ||
921 | items[i].function = clipboard_paste; | ||
922 | i++; | ||
923 | } | ||
924 | } | ||
638 | 925 | ||
639 | if (context == CONTEXT_TREE) | 926 | if (context == CONTEXT_TREE) |
640 | { | 927 | { |