Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5086)
+++ ChangeLog	(working copy)
@@ -1,3 +1,33 @@
+2009-02-27  Andrés G. Aragoneses  <aaragoneses@novell.com>
+
+	Fixes most cases of BGO#564355.
+
+	* src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs: Make Uris
+	consistent in formatting (now they are escaped regardless if they are
+	relative or not).
+
+	* src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs:
+	Migrate to escape relative Uris in previous versions of databases.
+
+	* src/Core/Banshee.Services/Banshee.Query/BansheeQuery.cs: Use the new
+	type UriQueryValue for UriField.
+
+	* src/Libraries/Hyena/Hyena.Query/UriQueryValue.cs: New file to 
+	handle the proper escaping for queries against Uris.
+
+	* src/Libraries/Hyena/Hyena.csproj
+	* src/Libraries/Hyena/Makefile.am: Add new file UriQueryValue.cs.
+
+	* src/Libraries/Hyena/Hyena/StringUtil.cs:
+	* src/Libraries/Hyena/Hyena.Query/ExactStringQueryValue.cs: Changes to
+	be able to reuse behaviour in derived classes.	
+
+	* src/Libraries/Hyena/Hyena.Query/Tests/QueryTests.cs: Added new tests
+	for Uri queries.
+
+	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs: Added new function
+	used by the DB migrator.
+
 2009-02-27  Gabriel Burt  <gabriel.burt@gmail.com>
 
 	* src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs: Rename
Index: src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs
===================================================================
--- src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs	(revision 5086)
+++ src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs	(working copy)
@@ -204,7 +204,7 @@
         public virtual SafeUri UriAndTypeToSafeUri (TrackUriType type, string uri_field)
         {
             if (type == TrackUriType.RelativePath && BaseDirectory != null)
-                return new SafeUri (System.IO.Path.Combine (BaseDirectory, uri_field));
+                return new SafeUri (System.IO.Path.Combine (BaseDirectory, Uri.UnescapeDataString (uri_field)));
             else
                 return new SafeUri (uri_field);
         }
@@ -215,6 +215,8 @@
             type = (uri_field == null) ? TrackUriType.AbsoluteUri : TrackUriType.RelativePath;
             if (uri_field == null) {
                 uri_field = uri.AbsoluteUri;
+            } else {
+                uri_field = Uri.EscapeUriString (uri_field);
             }
         }
 
Index: src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
===================================================================
--- src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	(revision 5086)
+++ src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	(working copy)
@@ -52,7 +52,7 @@
         // NOTE: Whenever there is a change in ANY of the database schema,
         //       this version MUST be incremented and a migration method
         //       MUST be supplied to match the new version number
-        protected const int CURRENT_VERSION = 26;
+        protected const int CURRENT_VERSION = 27;
         protected const int CURRENT_METADATA_VERSION = 5;
         
 #region Migration Driver
@@ -592,6 +592,28 @@
         
 #endregion

+#region Version 27
+
+        [DatabaseVersion (27)]
+        private bool Migrate_27 ()
+        {
+            Execute ("UPDATE CoreTracks SET Uri = HYENA_ESCAPE_URI(Uri) WHERE UriType = 1");
+
+            return true;
+        }
+        
+#endregion
+
 #pragma warning restore 0169
         
 #region Fresh database setup
Index: src/Core/Banshee.Services/Banshee.Query/BansheeQuery.cs
===================================================================
--- src/Core/Banshee.Services/Banshee.Query/BansheeQuery.cs	(revision 5086)
+++ src/Core/Banshee.Services/Banshee.Query/BansheeQuery.cs	(working copy)
@@ -261,7 +261,7 @@
 
         public static QueryField UriField = new QueryField (
             "uri", "Uri",
-            Catalog.GetString ("File Location"), "CoreTracks.Uri", typeof(ExactStringQueryValue),
+            Catalog.GetString ("File Location"), "CoreTracks.Uri", typeof(UriQueryValue),
             // Translators: These are unique search fields.  Please, no spaces. Blank ok.
             Catalog.GetString ("uri"), Catalog.GetString ("path"), Catalog.GetString ("file"), Catalog.GetString ("location"),
             "uri", "path", "file", "location"
Index: src/Libraries/Hyena/Hyena.Query/ExactStringQueryValue.cs
===================================================================
--- src/Libraries/Hyena/Hyena.Query/ExactStringQueryValue.cs	(revision 5086)
+++ src/Libraries/Hyena/Hyena.Query/ExactStringQueryValue.cs	(working copy)
@@ -33,7 +33,12 @@
     {
         public override string ToSql (Operator op)
         {
-            return String.IsNullOrEmpty (value) ? null : EscapeString (op, value.ToLower ());
+            return String.IsNullOrEmpty (value) ? null : EscapeExact (op, value);
         }
+
+        protected static string EscapeExact (Operator op, string orig)
+        {
+            return EscapeString (op, orig.ToLower ());
+        }
     }
 }
Index: src/Libraries/Hyena/Hyena.Query/UriQueryValue.cs
===================================================================
--- src/Libraries/Hyena/Hyena.Query/UriQueryValue.cs	(revision 0)
+++ src/Libraries/Hyena/Hyena.Query/UriQueryValue.cs	(revision 0)
@@ -0,0 +1,47 @@
+//
+// UriQueryValue.cs
+//
+// Authors:
+//   Andrés G. Aragoneses <aaragoneses@novell.com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// 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 Hyena;
+
+namespace Hyena.Query
+{
+    public class UriQueryValue : ExactStringQueryValue
+    {
+        public override string ToSql (Operator op)
+        {
+            if (String.IsNullOrEmpty (value))
+                return null;
+
+            string ret = Uri.EscapeDataString (value);
+
+            return EscapeExact (op, ret);
+        }
+    }
+}
Index: src/Libraries/Hyena/Hyena.Query/Tests/QueryTests.cs
===================================================================
--- src/Libraries/Hyena/Hyena.Query/Tests/QueryTests.cs	(revision 5086)
+++ src/Libraries/Hyena/Hyena.Query/Tests/QueryTests.cs	(working copy)
@@ -69,8 +69,14 @@
             "type", "mimetype", "format", "ext", "mime"
         );
 
+        private static QueryField UriField = new QueryField (
+            "uri", "Uri",
+            "File Location", "CoreTracks.Uri", typeof(UriQueryValue),
+            "uri", "path", "file", "location"
+        );
+
         private static QueryFieldSet FieldSet = new QueryFieldSet (
-            ArtistField, AlbumField, PlayCountField, MimeTypeField, DurationField
+            ArtistField, AlbumField, PlayCountField, MimeTypeField, DurationField, UriField
         );
 
         [Test]
@@ -170,6 +176,18 @@
             );
         }
 
+        [Test] // http://bugzilla.gnome.org/show_bug.cgi?id=564355
+        public void ParseUris ()
+        {
+            QueryValue val = new UriQueryValue ();
+            val.ParseUserQuery ("Dir With  Spaces And More+!");
+
+            Assert.AreEqual (
+                "(CoreTracks.Uri LIKE '%dir\\%20with\\%20\\%20spaces\\%20and\\%20more\\%2b!%' ESCAPE '\\' AND CoreTracks.Uri IS NOT NULL)",
+                UriField.ToSql (StringQueryValue.Contains, val)
+            );
+        }
+
         [Test] // http://bugzilla.gnome.org/show_bug.cgi?id=570312
         public void EscapeSqliteWildcards1 ()
         {
Index: src/Libraries/Hyena/Makefile.am
===================================================================
--- src/Libraries/Hyena/Makefile.am	(revision 5086)
+++ src/Libraries/Hyena/Makefile.am	(working copy)
@@ -79,6 +79,7 @@
 	Hyena.Query/StringQueryValue.cs \
 	Hyena.Query/Tests/QueryTests.cs \
 	Hyena.Query/TimeSpanQueryValue.cs \
+	Hyena.Query/UriQueryValue.cs \
 	Hyena.Query/UserQueryParser.cs \
 	Hyena.Query/XmlQueryParser.cs \
 	Hyena.SExpEngine/ArithmeticFunctionSet.cs \
Index: src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs
===================================================================
--- src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs	(revision 5086)
+++ src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteUtils.cs	(working copy)
@@ -143,4 +143,14 @@
             return Hyena.StringUtil.SearchKey (args[0] as string);
         }
     }
+
+    // for now, this is only used in BansheeDbFormatMigrator
+    [SqliteFunction (Name = "HYENA_ESCAPE_URI", FuncType = FunctionType.Scalar, Arguments = 1)]
+    internal class EscapeUriFunction : SqliteFunction
+    {
+        public override object Invoke (object[] args) {
+            return Uri.EscapeDataString (args[0] as string);
+        }
+    }
+
 }
