Index: apps/misc.h
===================================================================
--- apps/misc.h	(revision 18276)
+++ apps/misc.h	(working copy)
@@ -111,6 +111,7 @@
 #endif
 
 int open_utf8(const char* pathname, int flags);
+bool file_copy(const char* src, const char* target);
 
 #ifdef BOOTFILE
 #if !defined(USB_NONE) && !defined(USB_IPODSTYLE)
Index: apps/playlist.c
===================================================================
--- apps/playlist.c	(revision 18276)
+++ apps/playlist.c	(working copy)
@@ -71,6 +71,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include "sscanf.h"
 #include "playlist.h"
 #include "ata_idle_notify.h"
 #include "file.h"
@@ -705,6 +706,8 @@
         return -1;
     }
 
+    playlist->filename[0] = '\0';
+    
     switch (position)
     {
         case PLAYLIST_PREPEND:
@@ -1854,6 +1857,11 @@
 
     mutex_lock(&playlist->control_mutex);
 
+    if (playlist->bmark_fd >= 0)
+    {
+        close(playlist->bmark_fd); 
+        playlist->bmark_fd = -1;
+    }
     cache = &(playlist->control_cache[playlist->num_cached++]);
 
     cache->command = command;
@@ -1936,6 +1944,7 @@
         "%s", PLAYLIST_CONTROL_FILE);
     playlist->fd = -1;
     playlist->control_fd = -1;
+    playlist->bmark_fd = -1;
     playlist->max_playlist_size = global_settings.max_files_in_playlist;
     playlist->indices = buffer_alloc(
         playlist->max_playlist_size * sizeof(int));
@@ -2291,6 +2300,9 @@
                     case '#':
                         current_command = PLAYLIST_COMMAND_COMMENT;
                         break;
+                    case 'B':
+                        current_command = PLAYLIST_COMMAND_RESUMEPOINT;
+                        break;
                     default:
                         result = -1;
                         exit_loop = true;
@@ -3608,3 +3620,101 @@
 
     return result;
 }
+    
+bool playlist_add_bookmark(const char *bmark_filename, bool createnew)
+{
+    struct playlist_info *pl = &current_playlist;
+    struct playlist_resume_point resume_pt;
+    /* grab the currently playing track */
+    struct mp3entry *id3 = audio_current_track();
+    if(!id3)
+        return false;
+    resume_pt.track_position = id3->offset;
+    playlist_get_resume_info(&resume_pt.playlist_index);
+    sync_control(pl, true);
+    
+    if (createnew || pl->bmark_fd < 0)
+    {
+        if (pl->bmark_fd >= 0)
+            close(pl->bmark_fd);
+        if (file_copy(PLAYLIST_CONTROL_FILE, bmark_filename) == false)
+            return false;
+        pl->bmark_fd = open(bmark_filename, O_RDWR|O_APPEND);
+        if (pl->bmark_fd < 0)
+            return false;
+    }
+    fdprintf(pl->bmark_fd, "B:%d:%ld\n", resume_pt.playlist_index, resume_pt.track_position);
+    return true;
+}
+
+/* setup the playlist from a bmark file and find any resume points in the bmark
+   if successful *resumes_count will be set to the number of available resumes
+   current_playlist.bmark_fd will also be set the to correct file and at the end
+   and ready to add new points if the playlist isnt changed */
+bool playlist_resume_bookmark(const char *bmark_filename, bool get_last_point,
+                              struct playlist_resume_point *resumes, int *resumes_count)
+{
+    int maxresumes = *resumes_count, i=0;
+    struct playlist_info *pl = &current_playlist;
+    char buf[MAX_PATH];
+    *resumes_count = 0;
+    playlist_close(pl); /* may not be the best way to do this */
+    if (file_copy(bmark_filename, PLAYLIST_CONTROL_FILE) == false)
+        return false;
+    if (playlist_resume() >= 0)
+    {
+        /* playlist is loaded, open the origional bmark file and find any resume points */
+        pl->bmark_fd = open(bmark_filename, O_RDWR);
+        if (pl->bmark_fd < 0)
+            return false;
+        while (read_line(pl->bmark_fd, buf, MAX_PATH) > 0 &&
+               ((*resumes_count < maxresumes) || get_last_point))
+        {
+            if (buf[0] == 'B')
+            {
+                struct playlist_resume_point *r = &resumes[i];
+                if (sscanf(buf, "B:%d:%ld", &r->playlist_index, &r->track_position) == 2)
+                {
+                    (*resumes_count)++;
+                    if (!get_last_point)
+                        i++;
+                }
+            }
+        }
+        lseek(pl->bmark_fd, SEEK_END, 0);
+        return true;
+    }
+    return false;
+}
+
+#define PREVIOUS_BMARK_FILE ROCKBOX_DIR "/previous.bmark"
+bool playlist_backup_current(void)
+{
+    struct playlist_info *pl = &current_playlist;
+    struct playlist_resume_point resume_pt;
+    /* grab the currently playing track */
+    struct mp3entry *id3 = audio_current_track();
+    int fd;
+    if(!id3)
+        return false;
+    resume_pt.track_position = id3->offset;
+    playlist_get_resume_info(&resume_pt.playlist_index);
+    sync_control(pl, true);
+    if (file_copy(PLAYLIST_CONTROL_FILE, PREVIOUS_BMARK_FILE) == false)
+        return false;
+    fd = open(PREVIOUS_BMARK_FILE, O_WRONLY|O_APPEND);
+    if (fd < 0)
+        return false;
+    fdprintf(fd, "B:%d:%ld\n", resume_pt.playlist_index, resume_pt.track_position);
+    close(fd);
+    return true;
+}
+bool playlist_resume_backup(void)
+{
+    struct playlist_resume_point resumes;
+    int resume_count = 1;
+    if (!playlist_resume_bookmark(PREVIOUS_BMARK_FILE, true, &resumes, &resume_count) || resume_count < 1)
+        return false;
+    playlist_start(resumes.playlist_index,resumes.track_position);
+    return true;
+}
Index: apps/playlist.h
===================================================================
--- apps/playlist.h	(revision 18276)
+++ apps/playlist.h	(working copy)
@@ -42,7 +42,8 @@
     PLAYLIST_COMMAND_SHUFFLE,
     PLAYLIST_COMMAND_UNSHUFFLE,
     PLAYLIST_COMMAND_RESET,
-    PLAYLIST_COMMAND_COMMENT
+    PLAYLIST_COMMAND_COMMENT,
+    PLAYLIST_COMMAND_RESUMEPOINT
 };
 
 enum {
@@ -76,6 +77,8 @@
     int  fd;             /* descriptor of the open playlist file    */
     int  control_fd;     /* descriptor of the open control file     */
     bool control_created; /* has control file been created?         */
+    int  bmark_fd;       /* fd of the bmark file if it exists. set to -1 if
+                            the control changes and it exists       */
     int  dirlen;         /* Length of the path to the playlist file */
     unsigned long *indices; /* array of indices                     */
     const struct dircache_entry **filenames; /* Entries from dircache */
@@ -113,6 +116,12 @@
     int  display_index;      /* index of track for display          */
 };
 
+struct playlist_resume_point
+{
+    int playlist_index; /* index into the playlist for the current track */
+    long track_position; /* position in the current song to resume from */
+};
+
 /* Exported functions only for current playlist. */
 void playlist_init(void);
 void playlist_shutdown(void);
@@ -168,4 +177,11 @@
                                    void* context);
 int playlist_remove_all_tracks(struct playlist_info *playlist);
 
+/* bookmark stuff */
+bool playlist_add_bookmark(const char *bmark_filename, bool createnew);
+bool playlist_resume_bookmark(const char *bmark_filename, bool get_last_point,
+                struct playlist_resume_point *resumes, int *resumes_count);
+bool playlist_backup_current(void);
+bool playlist_resume_backup(void);
+
 #endif /* __PLAYLIST_H__ */
Index: apps/onplay.c
===================================================================
--- apps/onplay.c	(revision 18276)
+++ apps/onplay.c	(working copy)
@@ -684,77 +684,10 @@
 /* Paste a file to a new directory. Will overwrite always. */
 static bool clipboard_pastefile(const char *src, const char *target, bool copy)
 {
-    int src_fd, target_fd;
-    size_t buffersize;
-    ssize_t size, bytesread, byteswritten;
-    char *buffer;
     bool result = false;
 
     if (copy) {
-        /* See if we can get the plugin buffer for the file copy buffer */
-        buffer = (char *) plugin_get_buffer(&buffersize);
-        if (buffer == NULL || buffersize < 512) {
-            /* Not large enough, try for a disk sector worth of stack
-               instead */
-            buffersize = 512;
-            buffer = (char *) __builtin_alloca(buffersize);
-        }
-
-        if (buffer == NULL) {
-            return false;
-        }
-
-        buffersize &= ~0x1ff;  /* Round buffer size to multiple of sector
-                                  size */
-
-        src_fd = open(src, O_RDONLY);
-
-        if (src_fd >= 0) {
-            target_fd = creat(target);
-
-            if (target_fd >= 0) {
-                result = true;
-
-                size = filesize(src_fd);
-
-                if (size == -1) {
-                    result = false;
-                }
-
-                while(size > 0) {
-                    bytesread = read(src_fd, buffer, buffersize);
-
-                    if (bytesread == -1) {
-                        result = false;
-                        break;
-                    }
-
-                    size -= bytesread;
-
-                    while(bytesread > 0) {
-                        byteswritten = write(target_fd, buffer, bytesread);
-
-                        if (byteswritten == -1) {
-                            result = false;
-                            size = 0;
-                            break;
-                        }
-
-                        bytesread -= byteswritten;
-                        draw_slider();
-                    }
-                }
-
-                close(target_fd);
-
-                /* Copy failed. Cleanup. */
-                if (!result) {
-                    remove(target);
-                }
-            }
-
-            close(src_fd);
-        }
+        result = file_copy(src, target);
     } else {
         result = rename(src, target) == 0;
 #ifdef HAVE_MULTIVOLUME
Index: apps/filetree.c
===================================================================
--- apps/filetree.c	(revision 18276)
+++ apps/filetree.c	(working copy)
@@ -491,7 +491,10 @@
 
             case FILE_ATTR_BMARK:
                 gui_syncsplash(0, ID2P(LANG_WAIT));
-                bookmark_load(buf, false);
+                if (bookmark_load(buf, false) == true)
+                {
+                    start_wps = true;
+                }
                 reload_dir = true;
                 break;
 
Index: apps/bookmark.c
===================================================================
--- apps/bookmark.c	(revision 18276)
+++ apps/bookmark.c	(working copy)
@@ -110,7 +110,24 @@
 /* ----------------------------------------------------------------------- */
 bool bookmark_create_menu(void)
 {
-    write_bookmark(true, create_bookmark());
+    char buffer[MAX_PATH];
+    char* name = playlist_get_name(NULL, buffer, MAX_PATH);
+    if (name == NULL)
+        create_numbered_filename(buffer, "/", "bmark_",
+                                 ".bmark", 2 IF_CNFN_NUM_(, NULL));
+    else if (!strcmp("/", buffer))
+        strcpy(buffer, "/root_dir.bmark");
+    else
+    {
+        int len = strlen(name);
+        if(buffer[len-1] == '/')
+            len--;
+        strcpy(&buffer[len], ".bmark");
+    }
+    int lang_id = playlist_add_bookmark(buffer, false) ?
+                  LANG_BOOKMARK_CREATE_SUCCESS :
+                  LANG_BOOKMARK_CREATE_FAILURE;
+    gui_syncsplash(HZ, ID2P(lang_id));
     return false;
 }
 
@@ -415,44 +432,75 @@
 
 /* ----------------------------------------------------------------------- */
 /* This function loads the bookmark information into the resume memory.    */
-/* This is an interface function.                                          */
 /* ------------------------------------------------------------------------*/
-bool bookmark_load(const char* file, bool autoload)
+
+static char bookmark_resume_points[MAX_BOOKMARKS][MAX_BOOKMARK_SIZE];
+static int selection = -1;
+char * bmark_get_name(int selected_item, void * data,
+                     char * buffer, size_t buffer_len)
 {
-    int  fd;
-    char* bookmark = NULL;
-
-    if(autoload)
+    (void)buffer; (void)buffer_len; (void)data;
+    return bookmark_resume_points[selected_item];
+}
+int bmark_action_callback(int action, struct gui_synclist *lists)
+{
+    if (action == ACTION_STD_OK)
     {
-        fd = open(file, O_RDONLY);
-        if(fd >= 0)
-        {
-            if(read_line(fd, global_read_buffer, sizeof(global_read_buffer)) > 0)
-                bookmark=global_read_buffer;
-            close(fd);
-        }
+        selection = lists->selected_item;
+        return ACTION_STD_CANCEL;
     }
-    else
+    if (action == ACTION_STD_CANCEL)
+        selection = -1;
+    return action;
+}
+bool bookmark_load(const char* file, bool autoload)
+{
+    struct playlist_resume_point resumes[MAX_BOOKMARKS];
+    int resume_count = MAX_BOOKMARKS;
+    int i;
+    struct playlist_track_info info;
+    int audio_playing = audio_status();
+    /* dump the current playlist and position incase the user wants to cancel */
+    if (audio_playing)
+        playlist_backup_current();
+    
+    if (playlist_resume_bookmark(file, false, resumes, &resume_count) && resume_count > 0)
     {
-        /* This is not an auto-load, so list the bookmarks */
-        bookmark = select_bookmark(file, false);
-    }
-
-    if (bookmark != NULL)
-    {
-        if (!play_bookmark(bookmark))
+        if (resume_count > 1)
         {
-            /* Selected bookmark not found. */
-            if (!autoload)
+            for (i=0;i<resume_count;i++)
             {
-                gui_syncsplash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
+                if (playlist_get_track_info(NULL, resumes[i].playlist_index, &info) > -1)
+                {
+                    snprintf(bookmark_resume_points[i], MAX_BOOKMARK_SIZE, "%s: %d",
+                             info.filename, resumes[i].track_position);
+                }
             }
-            
-            return false;
+            struct simplelist_info list;
+            simplelist_info_init(&list, ID2P(LANG_BOOKMARK_SELECT_BOOKMARK),
+                                 resume_count, NULL);
+            list.action_callback = bmark_action_callback;
+            list.get_name = bmark_get_name;
+            selection = -1;
+            simplelist_show_list(&list);
+            if (selection == -1)
+            {
+                if (audio_playing)
+                    return playlist_resume_backup();
+                return false;
+            }
         }
+        else
+            selection = 0;
+        
+        playlist_start(resumes[selection].playlist_index,
+                       resumes[selection].track_position);
+        return true;
     }
-
-    return true;
+    else if (audio_playing)
+        return playlist_resume_backup();
+        
+    return false;
 }
 
 
Index: apps/misc.c
===================================================================
--- apps/misc.c	(revision 18276)
+++ apps/misc.c	(working copy)
@@ -55,6 +55,7 @@
 #include "sound.h"
 #include "playlist.h"
 #include "yesno.h"
+#include "plugin.h"
 
 #ifdef HAVE_MMC
 #include "ata_mmc.h"
@@ -1208,7 +1209,79 @@
     return fd;
 }
 
+/** Copy a file from src to dst **/
+bool file_copy(const char* src, const char* target)
+{
+    int src_fd, target_fd;
+    size_t buffersize;
+    ssize_t size, bytesread, byteswritten;
+    char *buffer;
+    bool result = false;
+    /* See if we can get the plugin buffer for the file copy buffer */
+    buffer = (char *) plugin_get_buffer(&buffersize);
+    if (buffer == NULL || buffersize < 512) {
+            /* Not large enough, try for a disk sector worth of stack
+        instead */
+        buffersize = 512;
+        buffer = (char *) __builtin_alloca(buffersize);
+    }
 
+    if (buffer == NULL) {
+        return false;
+    }
+
+    buffersize &= ~0x1ff;  /* Round buffer size to multiple of sector
+    size */
+
+    src_fd = open(src, O_RDONLY);
+
+    if (src_fd >= 0) {
+        target_fd = creat(target);
+
+        if (target_fd >= 0) {
+            result = true;
+
+            size = filesize(src_fd);
+
+            if (size == -1) {
+                result = false;
+            }
+
+            while(size > 0) {
+                bytesread = read(src_fd, buffer, buffersize);
+
+                if (bytesread == -1) {
+                    result = false;
+                    break;
+                }
+
+                size -= bytesread;
+
+                while(bytesread > 0) {
+                    byteswritten = write(target_fd, buffer, bytesread);
+
+                    if (byteswritten == -1) {
+                        result = false;
+                        size = 0;
+                        break;
+                    }
+
+                    bytesread -= byteswritten;
+         //          draw_slider();
+                }
+            }
+
+            close(target_fd);
+
+            /* Copy failed. Cleanup. */
+            if (!result) {
+                remove(target);
+            }
+        }
+        close(src_fd);
+    }
+    return result;
+}
 #ifdef HAVE_LCD_COLOR
 /*
  * Helper function to convert a string of 6 hex digits to a native colour
