Index: apps/Makefile
===================================================================
RCS file: /cvsroot/rockbox/apps/Makefile,v
retrieving revision 1.105
diff -u -r1.105 Makefile
--- apps/Makefile	3 Apr 2006 21:11:10 -0000	1.105
+++ apps/Makefile	23 May 2006 23:03:27 -0000
@@ -55,7 +55,7 @@
 endif
 
 CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET) $(DEFINES) -DTARGET_ID=$(TARGET_ID)	\
- -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE}
+ -DTARGET_NAME=\"$(ARCHOS)\" -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE}
 
 OBJS2 := $(OBJDIR)/lang.o $(patsubst %.c, $(OBJDIR)/%.o, $(SRC))
 OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2))
Index: apps/SOURCES
===================================================================
RCS file: /cvsroot/rockbox/apps/SOURCES,v
retrieving revision 1.44
diff -u -r1.44 SOURCES
--- apps/SOURCES	26 Mar 2006 11:33:41 -0000	1.44
+++ apps/SOURCES	23 May 2006 23:03:27 -0000
@@ -27,6 +27,9 @@
 tree.c
 tagtree.c
 filetree.c
+#ifdef CONFIG_RTC
+scrobbler.c
+#endif
 
 screen_access.c
 gui/buttonbar.c
Index: apps/main.c
===================================================================
RCS file: /cvsroot/rockbox/apps/main.c,v
retrieving revision 1.170
diff -u -r1.170 main.c
--- apps/main.c	1 May 2006 12:54:21 -0000	1.170
+++ apps/main.c	23 May 2006 23:03:27 -0000
@@ -88,6 +88,10 @@
 #include "lcd-remote.h"
 #endif
 
+#ifdef CONFIG_RTC
+#include "scrobbler.h"
+#endif
+
 /*#define AUTOROCK*/ /* define this to check for "autostart.rock" on boot */
 
 const char appsversion[]=APPSVERSION;
@@ -432,6 +436,10 @@
     pcm_rec_init();
 #endif
 
+#ifdef CONFIG_RTC
+    scrobbler_init();
+#endif
+
     /* runtime database has to be initialized after audio_init() */
     cpu_boost(false);
 
Index: apps/playback.c
===================================================================
RCS file: /cvsroot/rockbox/apps/playback.c,v
retrieving revision 1.315
diff -u -r1.315 playback.c
--- apps/playback.c	15 May 2006 02:37:06 -0000	1.315
+++ apps/playback.c	23 May 2006 23:03:29 -0000
@@ -267,6 +267,9 @@
 static void audio_fill_file_buffer(
         bool start_play, bool rebuffer, size_t offset);
 
+/* Play time of the previous track */
+unsigned long prev_track_elapsed;
+
 static void swap_codec(void)
 {
     int my_codec = current_codec;
@@ -1994,6 +1997,8 @@
 static bool load_next_track(void) {
     struct event ev;
 
+    prev_track_elapsed = cur_ti->id3.elapsed;
+
     if (ci.seek_time)
         codec_seek_complete_callback();
 
@@ -2041,6 +2046,11 @@
     }
 }
 
+unsigned long ret_prev_elapsed(void)
+{
+    return prev_track_elapsed;
+}
+
 static bool voice_request_next_track_callback(void)
 {
     ci_voice.new_track = 0;
Index: apps/scrobbler.c
===================================================================
RCS file: apps/scrobbler.c
diff -N apps/scrobbler.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ apps/scrobbler.c	23 May 2006 23:03:30 -0000
@@ -0,0 +1,295 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:$
+ *
+ * Copyright (C) 2006 Robert Keevil
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+/* mktime() code taken from lynx-2.8.5 source, written
+ by Philippe De Muyter <phdm@macqel.be>
+
+Audioscrobbler spec at:
+http://www.audioscrobbler.net/wiki/Portable_Player_Logging
+*/
+
+#include "file.h"
+#include "sprintf.h"
+#include "playback.h"
+#include "logf.h"
+#include "id3.h"
+#include "splash.h"
+#include "kernel.h"
+#include "audio.h"
+#ifndef SIMULATOR
+#include "ata.h"
+#endif
+#include "settings.h"
+#ifdef CONFIG_RTC
+#include "time.h"
+#include "timefuncs.h"
+#endif
+
+#include "scrobbler.h"
+
+#if defined(CONFIG_RTC) && !defined(SIMULATOR)
+typedef long time_t;
+#endif
+
+#define SCROBBLER_VERSION "1.0"
+#define SCROBBLER_FILE "/.scrobbler.log"
+
+/* increment this on any code change that effects output */
+/* replace with CVS Revision keyword? */
+#define SCROBBLER_REVISION "1.0"
+
+#define SCROBBLER_MAX_CACHE 7
+/* longest entry I've had is 323, add a safety margin */
+#define SCROBBLER_CACHE_LEN 511
+
+char scrobbler_cache[SCROBBLER_MAX_CACHE][SCROBBLER_CACHE_LEN];
+
+int scrobbler_fd = -1;
+int cache_pos;
+struct mp3entry scrobbler_entry;
+bool pending = false;
+bool scrobbler_initialized = false;
+time_t timestamp;
+
+static time_t mktime(struct tm *t)
+{
+    short month, year;
+    time_t	result;
+    static int	m_to_d[12] =
+        {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+    month = t->tm_mon;
+    year = t->tm_year + month / 12 + 1900;
+    month %= 12;
+    if (month < 0)
+    {
+        year -= 1;
+        month += 12;
+    }
+    result = (year - 1970) * 365 + (year - 1969) / 4 + m_to_d[month];
+    result = (year - 1970) * 365 + m_to_d[month];
+    if (month <= 1)
+        year -= 1;
+    result += (year - 1968) / 4;
+    result -= (year - 1900) / 100;
+    result += (year - 1600) / 400;
+    result += t->tm_mday;
+    result -= 1;
+    result *= 24;
+    result += t->tm_hour;
+    result *= 60;
+    result += t->tm_min;
+    result *= 60;
+    result += t->tm_sec;
+    return(result);
+}
+
+void write_cache(void)
+{
+    int i;
+
+    scrobbler_fd = open(SCROBBLER_FILE, O_RDWR | O_APPEND);
+    if(scrobbler_fd >= 0)
+    {
+        logf("SCROBBLER: writing %d entries", cache_pos); 
+        for ( i=0; i < cache_pos; i++ )
+        {
+            logf("SCROBBLER: write %d", i);
+            fdprintf(scrobbler_fd, "%s", scrobbler_cache[i]);
+        }
+        close(scrobbler_fd);
+    }
+    else
+    {
+        logf("SCROBBLER: error writing file");
+    }
+    cache_pos = 0;
+    scrobbler_fd = -1;
+}
+
+void add_to_cache(bool guess_time)
+{
+    /* FIXME  this should just be > but dies a horrible death */
+#ifdef SIMULATOR
+    if (cache_pos >= SCROBBLER_MAX_CACHE)
+#else
+    if ((cache_pos >= SCROBBLER_MAX_CACHE ) || ( ata_disk_is_active()) )
+#endif
+        write_cache();
+
+    int ret;
+    char rating = 0x53; /* "S" */;
+    
+    logf("SCROBBLER: add_to_cache %d", cache_pos);
+
+    if (guess_time)
+    {
+        if ((mktime(get_time()) - timestamp) >
+            (long)(scrobbler_entry.length/2000))
+            rating = 0x4C; /* "L" */
+    } else {
+        if ( ret_prev_elapsed() >
+            (scrobbler_entry.length/2) )
+            rating = 0x4C; /* "L" */
+    }
+
+    if (scrobbler_entry.album[0] == 0)
+        scrobbler_entry.album = "\t";
+
+    if (scrobbler_entry.tracknum > 0)
+    {
+        ret = snprintf(scrobbler_cache[cache_pos], 
+                sizeof(scrobbler_cache[cache_pos]),
+                "%s\t%s\t%s\t%d\t%d\t%c\t%ld\n",
+                scrobbler_entry.artist,
+                scrobbler_entry.album,
+                scrobbler_entry.title,
+                scrobbler_entry.tracknum,
+                (int)scrobbler_entry.length/1000,
+                rating,
+                (long)timestamp);
+    } else {
+        ret = snprintf(scrobbler_cache[cache_pos], 
+                sizeof(scrobbler_cache[cache_pos]),
+                "%s\t%s\t%s\t\t\t%d\t%c\t%ld\n",
+                scrobbler_entry.artist,
+                scrobbler_entry.album,
+                scrobbler_entry.title,
+                (int)scrobbler_entry.length/1000,
+                rating,
+                (long)timestamp);
+    }
+    if ( ret > SCROBBLER_CACHE_LEN )
+    {
+        logf("SCROBBLER: entry too long:");
+        logf("SCROBBLER: %s", scrobbler_entry.path);
+        /* only increment if a valid entry */
+        /* cache_pos--; */
+    } else
+        cache_pos++;
+}
+
+#if 0
+void scrobbler_debug(struct mp3entry *debug_entry)
+{
+    int sd_fd;
+    
+    sd_fd = open("/scrobbler-debug.log", O_RDONLY);
+    if(sd_fd < 0)
+    {
+        sd_fd = open("/scrobbler-debug.log", O_RDWR | O_CREAT);
+        if(sd_fd >= 0)
+        {
+            fdprintf(sd_fd, "#New file\n");
+            close(sd_fd);
+        }
+    }
+    close(sd_fd);
+    
+    sd_fd = open("/scrobbler-debug.log", O_RDWR | O_APPEND);
+    if(sd_fd >= 0)
+    {
+        logf("SCROBBLER: write %d", i);
+        fdprintf(sd_fd, "%s\n", debug_entry->path);
+        fdprintf(sd_fd, "%s\t%s\t%s\t%d\t%d\n",
+                debug_entry->artist,
+                debug_entry->album,
+                debug_entry->title,
+                debug_entry->tracknum,
+                (int)debug_entry->length/1000);
+        close(sd_fd);
+    }
+}
+#endif
+
+void scrobbler_change_event(struct mp3entry *id)
+{
+    /* scrobbler_debug(id); */
+    
+    if (pending)
+        add_to_cache(false);
+
+    /*  check if track was resumed > %50 played
+        check for blank artist or track name */
+    if ((id->elapsed > (id->length/2)) ||
+        (id->artist[0] == 0) ||
+        (id->title[0] == 0) )
+    {
+        pending = false; 
+        logf("SCROBBLER: skipping file %s", id->path);
+    }
+    else
+    {
+        copy_mp3entry(&scrobbler_entry, id);
+        timestamp = mktime(get_time());
+        pending = true;
+        /* cache_pos++; */ 
+    }
+}
+
+int scrobbler_init(void)
+{
+    if(!global_settings.audioscrobbler)
+        return -1;
+
+    scrobbler_fd = open(SCROBBLER_FILE, O_RDONLY);
+    if(scrobbler_fd < 0)
+    {
+        scrobbler_fd = open(SCROBBLER_FILE, O_RDWR | O_CREAT);
+        if(scrobbler_fd >= 0)
+        {
+            fdprintf(scrobbler_fd, "#AUDIOSCROBBLER/%s\n", SCROBBLER_VERSION);
+            fdprintf(scrobbler_fd, "#TZ/UNKNOWN\n");
+            fdprintf(scrobbler_fd, "#CLIENT/Rockbox %s %s\n", TARGET_NAME, SCROBBLER_REVISION);
+            close(scrobbler_fd);
+        }
+        else
+        {
+            logf("SCROBBLER: cannnot create log file");
+            return -1;
+        }
+    }
+    close(scrobbler_fd);
+    scrobbler_fd = -1;
+
+    audio_set_track_changed_event(&scrobbler_change_event);
+    cache_pos = 0;
+    pending = false;
+    scrobbler_initialized = true;
+
+    return 1;
+}
+
+void scrobbler_shutdown(void)
+{
+    /* add check for global_settings.scrobbler */
+    if (scrobbler_initialized)
+    {
+        if (pending)
+            add_to_cache(true);
+    
+        /* check that the last add_to_cache didn't fail */
+        if (cache_pos > 0)
+            write_cache();
+
+        pending = false;
+
+        audio_set_track_changed_event(NULL);
+        scrobbler_initialized = false;
+    }
+}
Index: apps/scrobbler.h
===================================================================
RCS file: apps/scrobbler.h
diff -N apps/scrobbler.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ apps/scrobbler.h	23 May 2006 23:03:30 -0000
@@ -0,0 +1,22 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:$
+ *
+ * Copyright (C) 2006 Robert Keevil
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+ 
+void scrobbler_change_event(struct mp3entry *id);
+int scrobbler_init(void);
+void scrobbler_shutdown(void);
Index: apps/settings.c
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.c,v
retrieving revision 1.387
diff -u -r1.387 settings.c
--- apps/settings.c	22 May 2006 16:40:40 -0000	1.387
+++ apps/settings.c	23 May 2006 23:03:31 -0000
@@ -563,6 +563,8 @@
     {1, S_O(warnon_erase_dynplaylist), false,
         "warn when erasing dynamic playlist", off_on },
 
+    {1, S_O(audioscrobbler), false, "Audioscrobbler Logging", off_on},
+
     /* If values are just added to the end, no need to bump the version. */
     /* new stuff to be added at the end */
 
Index: apps/settings.h
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.h,v
retrieving revision 1.218
diff -u -r1.218 settings.h
--- apps/settings.h	22 May 2006 16:40:40 -0000	1.218
+++ apps/settings.h	23 May 2006 23:03:32 -0000
@@ -494,6 +494,8 @@
 #ifdef HAVE_LCD_BITMAP
     unsigned char kbd_file[MAX_FILENAME+1]; /* last keyboard */
 #endif
+
+    bool audioscrobbler; /* pause ipods on headphone unplug */
 };
 
 enum optiontype { INT, BOOL };
Index: apps/settings_menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/settings_menu.c,v
retrieving revision 1.255
diff -u -r1.255 settings_menu.c
--- apps/settings_menu.c	22 May 2006 16:40:40 -0000	1.255
+++ apps/settings_menu.c	23 May 2006 23:03:35 -0000
@@ -1308,6 +1308,11 @@
     return rc;
 }
 
+static bool audioscrobbler(void)
+{
+    return set_bool( str(LANG_AUDIOSCROBBLER), &global_settings.audioscrobbler );
+}
+
 static bool codepage_setting(void)
 {
     static const struct opt_items names[] = {
@@ -1577,6 +1582,7 @@
 #endif
         { ID2P(LANG_TAGCACHE_FORCE_UPDATE), tagcache_force_update },
         { ID2P(LANG_RUNTIMEDB_ACTIVE), runtimedb },
+        { ID2P(LANG_AUDIOSCROBBLER), audioscrobbler},
     };
 
     bool old_shuffle = global_settings.playlist_shuffle;
Index: apps/tree.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tree.c,v
retrieving revision 1.404
diff -u -r1.404 tree.c
--- apps/tree.c	21 May 2006 11:00:01 -0000	1.404
+++ apps/tree.c	23 May 2006 23:03:35 -0000
@@ -79,6 +79,10 @@
 #include "backdrop.h"
 #endif
 
+#ifdef CONFIG_RTC
+#include "scrobbler.h"
+#endif
+
 /* a table for the know file types */
 const struct filetype filetypes[] = {
     { "mp3", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
@@ -1349,6 +1353,9 @@
 /* These two functions are called by the USB and shutdown handlers */
 void tree_flush(void)
 {
+#ifdef CONFIG_RTC
+    scrobbler_shutdown();
+#endif
     tagcache_stop_scan();
     playlist_shutdown();
 
@@ -1392,6 +1399,9 @@
             gui_textarea_clear(&screens[i]);
         }
     }
+#ifdef CONFIG_RTC
+    scrobbler_init();
+#endif
     tagcache_start_scan();
 #endif
 }
Index: apps/lang/english.lang
===================================================================
RCS file: /cvsroot/rockbox/apps/lang/english.lang,v
retrieving revision 1.251
diff -u -r1.251 english.lang
--- apps/lang/english.lang	22 May 2006 16:40:41 -0000	1.251
+++ apps/lang/english.lang	23 May 2006 23:03:38 -0000
@@ -8529,3 +8529,17 @@
     *: "Remote Scrolling Options"
   </voice>
 </phrase>
+<phrase>
+  id: LANG_AUDIOSCROBBLER
+  desc: "Audioscrobbler Log" in the playback menu
+  user:
+  <source>
+    *: "Audioscrobbler Log"
+  </source>
+  <dest>
+    *: "Audioscrobbler Log"
+  </dest>
+  <voice>
+    *: "Audioscrobbler Log"
+  </voice>
+</phrase>
Index: firmware/mpeg.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/mpeg.c,v
retrieving revision 1.359
diff -u -r1.359 mpeg.c
--- firmware/mpeg.c	30 Apr 2006 23:18:21 -0000	1.359
+++ firmware/mpeg.c	23 May 2006 23:03:43 -0000
@@ -108,6 +108,9 @@
 static unsigned int current_track_counter = 0;
 static unsigned int last_track_counter = 0;
 
+/* Play time of the previous track */
+unsigned long prev_track_elapsed;
+
 #ifndef SIMULATOR
 static int track_read_idx = 0;
 static int track_write_idx = 0;
@@ -1060,6 +1063,9 @@
 {
     DEBUGF("Track change\n");
 
+    struct trackdata *track = get_trackdata(0);
+    prev_track_elapsed = track->id3.elapsed;
+
 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
     /* Reset the AVC */
     sound_set_avc(-1);
@@ -1076,6 +1082,11 @@
     current_track_counter++;
 }
 
+unsigned long ret_prev_elapsed(void)
+{
+    return prev_track_elapsed;
+}
+
 #ifdef DEBUG
 void hexdump(const unsigned char *buf, int len)
 {
Index: firmware/export/audio.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/audio.h,v
retrieving revision 1.17
diff -u -r1.17 audio.h
--- firmware/export/audio.h	14 May 2006 23:34:24 -0000	1.17
+++ firmware/export/audio.h	23 May 2006 23:03:43 -0000
@@ -101,7 +101,7 @@
 unsigned long audio_num_recorded_bytes(void);
 void audio_set_spdif_power_setting(bool on);
 unsigned long audio_get_spdif_sample_rate(void);
-
+unsigned long ret_prev_elapsed(void);
 
 
 /***********************************************************************/
