diff --git a/src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs b/src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs
index 98d8114..deef405 100644
--- a/src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs
+++ b/src/Core/Banshee.Services/Banshee.Playlists.Formats/IPlaylistFormat.cs
@@ -31,9 +31,14 @@ using System.IO;
 using System.Collections.Generic;
 
 using Banshee.Sources;
+using Hyena;
 
 namespace Banshee.Playlists.Formats
 {
+    public delegate Uri Resolver(string uri);
+
+    public delegate string Exporter(SafeUri uri);
+
     public interface IPlaylistFormat
     {
         void Load(Stream stream, bool validateHeader);
@@ -47,5 +52,9 @@ namespace Banshee.Playlists.Formats
         Uri BaseUri { get; set; }
         string Title { get; set; }
         char FolderSeparator { get; set; }
+
+        Resolver UriResolver { get; set; }
+
+        Exporter UriExporter { get; set; }
     }
 }
diff --git a/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs b/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs
index 2889100..75a2bd9 100644
--- a/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs
+++ b/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs
@@ -77,16 +77,26 @@ namespace Banshee.Playlists.Formats
             return element;
         }
 
+        public Resolver UriResolver { get; set; }
+
         protected virtual Uri ResolveUri(string uri)
         {
+            if (UriResolver != null)
+                return UriResolver (uri);
+
             if (!uri.Contains (Folder.UnixSeparator.ToString ()) && uri.Contains (Folder.DosSeparator.ToString ())) {
                 uri = uri.Replace (Folder.DosSeparator, Folder.UnixSeparator);
             }
             return BaseUri == null ? new Uri(uri) : new Uri(BaseUri, uri);
         }
 
+        public Exporter UriExporter { get; set; }
+
         protected virtual string ExportUri(SafeUri uri)
         {
+            if (UriExporter != null)
+                return UriExporter (uri);
+
             if(BaseUri == null) {
                 return uri.IsLocalPath ? uri.LocalPath : uri.AbsoluteUri;
             }
diff --git a/src/Core/Banshee.Services/Banshee.Playlists.Formats/SymbianM3uPlaylistFormat.cs b/src/Core/Banshee.Services/Banshee.Playlists.Formats/SymbianM3uPlaylistFormat.cs
new file mode 100644
index 0000000..931b668
--- /dev/null
+++ b/src/Core/Banshee.Services/Banshee.Playlists.Formats/SymbianM3uPlaylistFormat.cs
@@ -0,0 +1,101 @@
+//
+// SymbianM3uPlaylistFormat.cs
+//
+// Author:
+//   Nicholas Little <arealityfarbetween@googlemail.com>
+//
+// Copyright (C) 2012
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Unix;
+
+using Banshee.Base;
+using Banshee.Collection;
+using Banshee.Sources;
+using Banshee.IO;
+using Hyena;
+
+using BansheeDir = Banshee.IO.Directory;
+
+namespace Banshee.Playlists.Formats
+{
+    public class SymbianM3uPlaylistFormat : M3uPlaylistFormat
+    {
+        public new static readonly PlaylistFormatDescription FormatDescription = new PlaylistFormatDescription(
+            typeof (SymbianM3uPlaylistFormat), MagicHandler, Catalog.GetString ("MPEG Version 3.0 Extended - Nokia Variant (*.m3u)"),
+            "m3u", new string [] {"audio/x-nokia-mpegurl", "audio/nokia-m3u", "audio/nokia-mpeg-url"});
+
+        public new static bool MagicHandler(StreamReader reader)
+        {
+            bool rv = M3uPlaylistFormat.MagicHandler(reader);
+
+            string line;
+            while (rv && (line = reader.ReadLine ()).StartsWith ("#"));
+
+            return rv && line.StartsWith ("E:");
+        }
+
+        public SymbianM3uPlaylistFormat()
+        {
+        }
+
+        /// <summary>
+        /// Use the path of the playlist to find the
+        /// mount point or drive.
+        /// </summary>
+        private string RootedAt {
+            get {
+                if (rooted_at == null) {
+    
+                    string base_path = BaseUri.AbsolutePath;
+        
+                    DriveInfo i = DriveInfo.GetDrives ()
+                            .OrderByDescending (x => x.RootDirectory.FullName.Length)
+                            .First (x => base_path.Contains (x.RootDirectory.FullName));
+
+                    rooted_at = (i == null || i.RootDirectory.FullName.Equals (BansheeDir.UnixSeparator))
+                        ? "" : i.RootDirectory.FullName;
+                }
+                return rooted_at;
+            }
+        }
+        private string rooted_at;
+
+        protected override string ExportUri (SafeUri uri)
+        {
+            uri = new SafeUri(uri.AbsoluteUri.Replace(RootedAt, "E:"));
+            return base.ExportUri(uri);
+        }
+
+        protected override Uri ResolveUri (string uri)
+        {
+            uri = uri.Replace(BansheeDir.DosSeparator, BansheeDir.UnixSeparator)
+                     .Replace("E:", RootedAt);
+            return base.ResolveUri(uri);
+        }
+    }
+}
diff --git a/src/Core/Banshee.Services/Banshee.Services.csproj b/src/Core/Banshee.Services/Banshee.Services.csproj
index b52262f..3bebb43 100644
--- a/src/Core/Banshee.Services/Banshee.Services.csproj
+++ b/src/Core/Banshee.Services/Banshee.Services.csproj
@@ -328,6 +320,7 @@
     <Compile Include="Banshee.Collection.Database\DatabaseYearListModel.cs" />
     <Compile Include="Banshee.Collection\InvalidFileException.cs" />
     <Compile Include="Banshee.Sources\IBatchScrobblerSource.cs" />
+    <Compile Include="Banshee.Playlists.Formats\SymbianM3uPlaylistFormat.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Banshee.Services.addin.xml">
diff --git a/src/Core/Banshee.Services/Makefile.am b/src/Core/Banshee.Services/Makefile.am
index 3bf10ae..2c6571f 100644
--- a/src/Core/Banshee.Services/Makefile.am
+++ b/src/Core/Banshee.Services/Makefile.am
@@ -161,6 +161,7 @@ SOURCES =  \
 	Banshee.Playlists.Formats/PlaylistFormatDescription.cs \
 	Banshee.Playlists.Formats/PlaylistParser.cs \
 	Banshee.Playlists.Formats/PlsPlaylistFormat.cs \
+	Banshee.Playlists.Formats/SymbianM3uPlaylistFormat.cs \
 	Banshee.Playlists.Formats/Tests/PlaylistFormatTests.cs \
 	Banshee.Playlists.Formats/XspfPlaylistFormat.cs \
 	Banshee.Preferences/Collection.cs \
diff --git a/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.addin.xml b/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.addin.xml
index 251e665..815f192 100644
--- a/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.addin.xml
+++ b/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.addin.xml
@@ -96,6 +96,11 @@
     <MassStorageDevice class="Banshee.Dap.MassStorage.NookDevice"
         vendor-name="Barnes and Noble" product-name="Nook Classic"
         vendor-id="0x2080" product-id="0x001"/>
+        
+    <MassStorageDevice class="Banshee.Dap.MassStorage.SymbianDevice"
+        vendor-name="Nokia" product-name="N95"
+        vendor-id="0x0421" product-id="0x04ed"/>
+        
   </Extension>
 
 </Addin>
diff --git a/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.csproj b/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.csproj
index d3126e1..f9b83ea 100644
--- a/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.csproj
+++ b/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.csproj
@@ -74,6 +72,7 @@
     <Compile Include="Banshee.Dap.MassStorage\MaemoDevice.cs" />
     <Compile Include="Banshee.Dap.MassStorage\NookDevice.cs" />
     <Compile Include="Banshee.Dap.MassStorage\RockBoxDevice.cs" />
+    <Compile Include="Banshee.Dap.MassStorage\SymbianDevice.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Banshee.Dap.MassStorage.addin.xml">
diff --git a/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs b/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
index 79c1e3e..7c4176d 100644
--- a/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
+++ b/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
@@ -177,6 +177,10 @@ namespace Banshee.Dap.MassStorage
                     PlaylistSource playlist = new PlaylistSource (name, this);
                     playlist.Save ();
                     //Hyena.Data.Sqlite.HyenaSqliteCommand.LogAll = true;
+
+                    if (OnSyncDone != null)
+                        OnSyncDone (this, new SyncEventArgs (playlist, loaded_playlist));
+
                     foreach (Dictionary<string, object> element in loaded_playlist.Elements) {
                         string track_path = (element["uri"] as Uri).LocalPath;
                         int track_id = DatabaseTrackInfo.GetTrackIdForUri (new SafeUri (track_path), DbId);
@@ -333,6 +337,21 @@ namespace Banshee.Dap.MassStorage
             }
         }
 
+        public class SyncEventArgs : EventArgs {
+            public SyncEventArgs(PlaylistSource src, IPlaylistFormat fmt) {
+                Source = src;
+                Format = fmt;
+            }
+
+            public PlaylistSource Source { get; set; }
+            public IPlaylistFormat Format { get; set; }
+        }
+
+        public delegate void SyncEventHandler(object src, SyncEventArgs args);
+
+        public event SyncEventHandler OnSyncStart;
+        public event SyncEventHandler OnSyncDone;
+
         public override void SyncPlaylists ()
         {
             if (!CanSyncPlaylists) {
@@ -368,6 +387,9 @@ namespace Banshee.Dap.MassStorage
                         stream = Banshee.IO.File.OpenWrite (playlist_path, true);
                         playlist_format.BaseUri = new Uri (PlaylistsWritePath);
 
+                        if (OnSyncStart != null)
+                            OnSyncStart (this, new SyncEventArgs (from, playlist_format));
+
                         playlist_format.Save (stream, from);
                     } catch (Exception e) {
                         Log.Exception (e);
diff --git a/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/SymbianDevice.cs b/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/SymbianDevice.cs
new file mode 100644
index 0000000..9e82560
--- /dev/null
+++ b/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/SymbianDevice.cs
@@ -0,0 +1,188 @@
+// 
+// SymbianDevice.cs
+// 
+// Author:
+//   Nicholas Little <arealityfarbetween@googlemail.com>
+// 
+// Copyright 2012
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+using Banshee.IO;
+using Banshee.Hardware;
+using Banshee.Sources;
+using System.Collections;
+using System.Collections.Generic;
+
+using Banshee.Playlist;
+using Banshee.Playlists.Formats;
+
+namespace Banshee.Dap.MassStorage
+{
+    public class SymbianDevice : CustomMassStorageDevice
+    {
+        #region MassStorageDevice Property Overrides
+        private static string[] icons = {
+                "phone-nokia-n95", DapSource.FallbackIcon
+        };
+        public override string [] GetIconNames ()
+        {
+            /*
+             * TODO: switch on device name and select icon
+             * appropriately, ala AndroidDevice
+             */
+            return icons;
+        }
+
+        protected override string DefaultFolderSeparator {
+            get { return Directory.DosSeparator.ToString(); }
+        }
+
+        private static string[] playlist_formats = { "audio/x-mpegurl" };
+        protected override string[] DefaultPlaylistFormats {
+            get { return playlist_formats; }
+        }
+
+        private static string[] audio_folders = { "Music/" };
+        protected override string[] DefaultAudioFolders {
+            get {
+                return audio_folders;
+            }
+        }
+
+        protected override int DefaultFolderDepth {
+            get {
+                return 2;
+            }
+        }
+
+        protected override string DefaultPlaylistPath {
+            get {
+                return "Playlists/";
+            }
+        }
+
+        private static string[] video_folders = { "My Videos/" };
+        protected override string[] DefaultVideoFolders {
+            get {
+                return video_folders;
+            }
+        }
+
+        private static string[] playback_mime_types = {
+            "audio/mp3",
+            "video/mp4"
+        };
+        protected override string[] DefaultPlaybackMimeTypes {
+            get {
+                return playback_mime_types;
+            }
+        }
+
+        private string default_name;
+        protected override string DefaultName {
+            get {
+                if (string.IsNullOrEmpty(default_name))
+                    default_name = string.Format("{0} {1}", VendorProductInfo.VendorName,
+                                                 VendorProductInfo.ProductName);
+                return default_name;
+            }
+        }
+
+        public override void SourceInitialize ()
+        {
+            Hyena.Log.DebugFormat ("SymbianDevice: Initialising Source...");
+
+            Source.OnSyncStart += (src, args) => {
+                if (args == null) 
+                    return;
+
+                args.Format.UriExporter = delegate (Hyena.SafeUri uri) {
+                    string rv = uri.AbsolutePath
+                        .Replace (Source.BaseDirectory, "E:")
+                        .Replace (Directory.UnixSeparator, Directory.DosSeparator);
+                    Hyena.Log.DebugFormat ("SymbianDevice, Exporting URI: {0} -> {1}", 
+                                           uri.AbsolutePath,
+                                           rv);
+                    return rv;
+
+                };
+            };
+            Source.OnSyncDone += (src, args) => { 
+                if (args == null) 
+                    return;
+
+
+                /*
+                 * It would be cheaper to do the same as above, and do the Resolution
+                 * ourselves as the playlist is generated but we can't get at it while
+                 * it's in PlaylistFileUtil.Load()
+                 */
+                string uri;
+                foreach (var i in args.Format.Elements) {
+
+                    uri = (i["uri"] as Uri).LocalPath
+                            .Replace (Directory.DosSeparator, Directory.UnixSeparator)
+                            .Replace ("E:", Source.BaseDirectory);
+
+                    Hyena.Log.DebugFormat ("SymbianDevice, Resolving: {0} -> {1}", 
+                                           (i["uri"] as Uri).LocalPath,
+                                           uri);
+
+                    i["uri"] = new Uri (uri);
+                }
+            };
+
+            Source.TracksAdded += HandleTracksAdded;
+            Source.TracksChanged += HandleTracksChanged;
+            Source.TracksDeleted += HandleTracksDeleted;
+        }
+
+        public override bool LoadDeviceConfiguration ()
+        {
+            LoadConfig ();
+
+            return true;
+        }
+        #endregion
+
+        #region Source Event Handlers, to support cover art
+        private void HandleTracksAdded (Source sender, TrackEventArgs args)
+        {
+            LogArgs ("Added", args);
+        }
+
+        private void HandleTracksChanged (Source sender, TrackEventArgs args)
+        {
+            LogArgs ("Changed", args);
+        }
+
+        private void HandleTracksDeleted (Source sender, TrackEventArgs args)
+        {
+            LogArgs ("Deleted", args);
+        }
+
+        private void LogArgs (string action, TrackEventArgs args) {
+            Hyena.Log.DebugFormat ("Tracks {0}: {1}", action, args != null ? args.ChangedFields : null);
+        }
+        #endregion
+    }
+}
+
diff --git a/src/Dap/Banshee.Dap.MassStorage/Makefile.am b/src/Dap/Banshee.Dap.MassStorage/Makefile.am
index 24e6490..4b3d329 100644
--- a/src/Dap/Banshee.Dap.MassStorage/Makefile.am
+++ b/src/Dap/Banshee.Dap.MassStorage/Makefile.am
@@ -14,6 +14,7 @@ SOURCES =  \
 	Banshee.Dap.MassStorage/MassStorageSource.cs \
 	Banshee.Dap.MassStorage/NookDevice.cs \
 	Banshee.Dap.MassStorage/RockBoxDevice.cs \
+	Banshee.Dap.MassStorage/SymbianDevice.cs \
 	Banshee.Dap.MassStorage/WebOSDevice.cs
 
 RESOURCES = Banshee.Dap.MassStorage.addin.xml
