? data/images/cc-by.png
? data/images/cc-by_nc.png
? data/images/cc-by_nc_nd.png
? data/images/cc-by_nc_sa.png
? data/images/cc-by_nd.png
? data/images/cc-by_sa.png
? data/images/cc-devnations.png
? data/images/cc-nc.png
? data/images/cc-nc_sa.png
? data/images/cc-nc_samplingplus.png
? data/images/cc-nd.png
? data/images/cc-nd_nc.png
? data/images/cc-publicdomain.png
? data/images/cc-sa.png
? data/images/cc-sampling.png
? data/images/cc-samplingplus.png
? src/Banshee.Base/Licenses.cs
? src/Banshee.Base/Gui/LicenseRenderer.cs
Index: data/banshee.glade
===================================================================
RCS file: /cvs/gnome/banshee/data/banshee.glade,v
retrieving revision 1.23
diff -u -p -r1.23 banshee.glade
--- data/banshee.glade	4 Aug 2006 20:43:31 -0000	1.23
+++ data/banshee.glade	6 Aug 2006 16:55:04 -0000
@@ -18,6 +18,7 @@
   <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
   <property name="focus_on_map">True</property>
   <property name="urgency_hint">False</property>
+  <signal name="delete_event" handler="OnWindowPlayerDeleteEvent" last_modification_time="Sat, 29 Jan 2005 07:50:08 GMT"/>
 
   <child>
     <widget class="GtkVBox" id="vbox1">
@@ -1496,7 +1497,7 @@
 	      <child>
 		<widget class="GtkTable" id="table2">
 		  <property name="visible">True</property>
-		  <property name="n_rows">4</property>
+		  <property name="n_rows">5</property>
 		  <property name="n_columns">4</property>
 		  <property name="homogeneous">False</property>
 		  <property name="row_spacing">5</property>
@@ -1897,6 +1898,62 @@
 		      <property name="y_options"></property>
 		    </packing>
 		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label80">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">License:</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">0</property>
+		      <property name="right_attach">1</property>
+		      <property name="top_attach">4</property>
+		      <property name="bottom_attach">5</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="License">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="label" translatable="yes">Unknown</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">True</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">True</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_MIDDLE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">1</property>
+		      <property name="right_attach">4</property>
+		      <property name="top_attach">4</property>
+		      <property name="bottom_attach">5</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
 		</widget>
 	      </child>
 	    </widget>
Index: data/images/Makefile.am
===================================================================
RCS file: /cvs/gnome/banshee/data/images/Makefile.am,v
retrieving revision 1.37
diff -u -p -r1.37 Makefile.am
--- data/images/Makefile.am	21 Jun 2006 01:43:56 -0000	1.37
+++ data/images/Makefile.am	6 Aug 2006 16:55:04 -0000
@@ -67,7 +67,24 @@ EXTRA_DIST = \
 	cd-action-burn-32.png \
 	cd-action-burn-48.png \
 	encode-action-24.png \
-	splash.png
+	splash.png \
+	cc-by_nc_nd.png \
+    cc-by_nc.png \
+    cc-by_nc_sa.png \
+    cc-by_nd.png \
+    cc-by.png \
+    cc-by_sa.png \
+    cc-devnations.png \
+    cc-nc.png \
+    cc-nc_samplingplus.png \
+    cc-nc_sa.png \
+    cc-nd_nc.png \
+    cc-nd.png \
+    cc-publicdomain.png \
+    cc-samplingplus.png \
+    cc-sampling.png \
+    cc-sa.png
+
 
 generate-resource-list:
 	for i in $(EXTRA_DIST); do \
Index: src/PlaylistView.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/PlaylistView.cs,v
retrieving revision 1.54
diff -u -p -r1.54 PlaylistView.cs
--- src/PlaylistView.cs	5 Aug 2006 20:51:12 -0000	1.54
+++ src/PlaylistView.cs	6 Aug 2006 16:55:05 -0000
@@ -62,7 +62,8 @@ namespace Banshee
             Time,
             Rating,
             PlayCount,
-            LastPlayed
+            LastPlayed,
+            License
         };
             
         private ArrayList columns;
@@ -77,6 +78,7 @@ namespace Banshee
         public PlaylistColumn RatingColumn;
         public PlaylistColumn PlaysColumn;
         public PlaylistColumn LastPlayedColumn;
+        public PlaylistColumn LicenseColumn;
         
         private class ColumnSorter : IComparer
         {
@@ -132,6 +134,12 @@ namespace Banshee
                 new CellRendererText(),
                 9, (int)ColumnId.LastPlayed);
             columns.Add(LastPlayedColumn);
+        	
+        	LicenseColumn = new PlaylistColumn(this, 
+                Catalog.GetString("License"), "License",
+                new TreeCellDataFunc(TrackCellLicense), new Banshee.Gui.LicenseRenderer(),
+                10, (int)ColumnId.License);
+            columns.Add(LicenseColumn);
             
             columns.Sort(new ColumnSorter());
             
@@ -209,6 +217,8 @@ namespace Banshee
                 new TreeIterCompareFunc(PlayCountTreeIterCompareFunc));
             model.SetSortFunc((int)ColumnId.LastPlayed, 
                 new TreeIterCompareFunc(LastPlayedTreeIterCompareFunc));
+            model.SetSortFunc((int)ColumnId.License, 
+                new TreeIterCompareFunc(LicenseTreeIterCompareFunc));
         }    
 
         private void OnRipToggled(object o, ToggledArgs args)
@@ -290,6 +300,19 @@ namespace Banshee
             return StringFieldCompare(model.IterTrackInfo(a).Genre, 
                 model.IterTrackInfo(b).Genre);
         }
+                
+        public int LicenseTreeIterCompareFunc(TreeModel _model, TreeIter a, 
+            TreeIter b)
+        {
+            if(model.IterTrackInfo(a).LicenseVerifyStatus == LicenseVerifyStatus.Invalid &&
+               model.IterTrackInfo(b).LicenseVerifyStatus != LicenseVerifyStatus.Invalid)
+                return -1;
+            else if(model.IterTrackInfo(b).LicenseVerifyStatus == LicenseVerifyStatus.Invalid &&
+                    model.IterTrackInfo(a).LicenseVerifyStatus != LicenseVerifyStatus.Invalid)
+                return 1;
+            else
+                return model.IterTrackInfo(a).License - model.IterTrackInfo(b).License;
+        }  
         
         public int YearTreeIterCompareFunc(TreeModel _model, TreeIter a,
             TreeIter b)
@@ -482,10 +505,21 @@ namespace Banshee
             if(ti == null) {
                 return;
             }
-            
+
             SetRendererAttributes((CellRendererText)cell, ti.Genre, iter);
         }
-        
+
+        protected void TrackCellLicense(TreeViewColumn tree_column,
+            CellRenderer cell, TreeModel tree_model, TreeIter iter)
+        {
+            TrackInfo ti = model.IterTrackInfo(iter);
+            if(ti == null) {
+                return;
+            }
+            
+            ((Banshee.Gui.LicenseRenderer)cell).Track = ti;
+        }
+
         protected void TrackCellYear(TreeViewColumn tree_column,
             CellRenderer cell, TreeModel tree_model, TreeIter iter)
         {
Index: src/TrackProperties.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/TrackProperties.cs,v
retrieving revision 1.28
diff -u -p -r1.28 TrackProperties.cs
--- src/TrackProperties.cs	21 Jun 2006 01:43:57 -0000	1.28
+++ src/TrackProperties.cs	6 Aug 2006 16:55:05 -0000
@@ -31,6 +31,7 @@ using Gtk;
 using Glade;
 using System.Collections;
 using Mono.Unix;
 
 using Banshee.Base;
 
@@ -256,6 +257,7 @@ namespace Banshee
                     Channels.Text = af.Channels.ToString();
                     MimeType.Text = af.MimeType;
                     ExtraInfo.Text = af.EncodingType;
+                    (glade["License"] as Label).Markup = GetLicenseText(track.Track);
                 } catch(Exception e) {
                     BitRate.Text = Catalog.GetString("Unknown");
                     SampleRate.Text = Catalog.GetString("Unknown");
@@ -263,11 +265,22 @@ namespace Banshee
                     Channels.Text = Catalog.GetString("Unknown");
                     MimeType.Text = Catalog.GetString("Unknown");
                     ExtraInfo.Text = Catalog.GetString("Unknown");
+                    (glade["License"] as Label).Markup = Catalog.GetString("Unknown");                    
                 }
             }
             
             Previous.Sensitive = index > 0;
             Next.Sensitive = index < TrackSet.Count - 1;
+        }
+        
+        private string GetLicenseText(TrackInfo track)
+        {
+            if(track.License == Licenses.Attributes.none) // No License
+                return "None";
+		    else if(track.LicenseVerifyStatus == LicenseVerifyStatus.Invalid) // Invalid License
+                return String.Format("{0} <small><i>(Invalid claim)</i></small>", track.LicenseUri);
+            else // Verify not attempted or has been Verified
+                return track.LicenseUri;
         }
         
         private void OnPreviousClicked(object o, EventArgs args)
Index: src/Banshee.Base/Database.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Database.cs,v
retrieving revision 1.7
diff -u -p -r1.7 Database.cs
--- src/Banshee.Base/Database.cs	22 May 2006 17:01:49 -0000	1.7
+++ src/Banshee.Base/Database.cs	6 Aug 2006 16:55:05 -0000
@@ -58,6 +58,7 @@ namespace Banshee.Base
                    	Label TEXT,
                    	Title TEXT,
                    	Genre TEXT,
+                   	
                    	Year INTEGER,
                    	
                    	TrackNumber INTEGER,
@@ -97,6 +98,20 @@ namespace Banshee.Base
                     ViewOrder INTEGER NOT NULL DEFAULT 0
                 )");
             }
+            
+            if(!TableExists("TrackLicenses")) {
+                Console.WriteLine("Creating tracklicenses table");
+                Execute(@"
+                CREATE TABLE TrackLicenses (
+                   	TrackID INTEGER PRIMARY KEY,
+                   	
+                   	License INTEGER,
+                   	Copyright TEXT,
+                   	LicenseURI TEXT,
+                   	MetadataURI TEXT,
+                   	LicenseVerifyStatus INTEGER
+                )");
+            }
         }
         
         private void CompatabilityUpdate()
@@ -128,6 +143,42 @@ namespace Banshee.Base
                 LogCore.Instance.PushDebug("Adding new database column", "ViewOrder INTEGER");
                 Execute("ALTER TABLE PlaylistEntries ADD ViewOrder INTEGER NOT NULL DEFAULT 0");
             }
+            
+            /* License Handling */
+            try {
+                QuerySingle("SELECT License FROM TrackLicenses LIMIT 1");
+            } catch(ApplicationException) {
+                LogCore.Instance.PushDebug("Adding new database column", "License INTEGER");
+                Execute("ALTER TABLE TrackLicenses ADD License INTEGER");
+            }
+  
+            try {
+                QuerySingle("SELECT Copyright FROM TrackLicenses LIMIT 1");
+            } catch(ApplicationException) {
+                LogCore.Instance.PushDebug("Adding new database column", "Copyright TEXT");
+                Execute("ALTER TABLE TrackLicenses ADD Copyright TEXT");
+            }
+  
+            try {
+                QuerySingle("SELECT LicenseURI FROM TrackLicenses LIMIT 1");
+            } catch(ApplicationException) {
+                LogCore.Instance.PushDebug("Adding new database column", "LicenseURI TEXT");
+                Execute("ALTER TABLE TrackLicenses ADD LicenseURI TEXT");
+            }
+
+            try {
+                QuerySingle("SELECT MetadataURI FROM TrackLicenses LIMIT 1");
+            } catch(ApplicationException) {
+                LogCore.Instance.PushDebug("Adding new database column", "MetadataURI TEXT");
+                Execute("ALTER TABLE TrackLicenses ADD MetadataURI TEXT");
+            }
+            
+            try {
+                QuerySingle("SELECT LicenseVerifyStatus FROM TrackLicenses LIMIT 1");
+            } catch(ApplicationException) {
+                LogCore.Instance.PushDebug("Adding new database column", "LicenseVerifyStatus INTEGER");
+                Execute("ALTER TABLE TrackLicenses ADD LicenseVerifyStatus INTEGER");
+            }   
         }
     }
 }
Index: src/Banshee.Base/Library.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Library.cs,v
retrieving revision 1.12
diff -u -p -r1.12 Library.cs
--- src/Banshee.Base/Library.cs	28 Jul 2006 17:49:47 -0000	1.12
+++ src/Banshee.Base/Library.cs	6 Aug 2006 16:55:06 -0000
@@ -220,7 +220,13 @@ namespace Banshee.Base
                     WHERE TrackID = '{0}'",
                     track.TrackId
             ));
-                        
+            
+            Db.Execute(String.Format(
+                @"DELETE FROM TrackLicenses
+                    WHERE TrackID = '{0}'",
+                    track.TrackId
+            ));         
+            
             LibraryTrackRemovedHandler removed_handler = TrackRemoved;
             if(removed_handler != null) {
                 LibraryTrackRemovedArgs args = new LibraryTrackRemovedArgs();
@@ -233,7 +239,8 @@ namespace Banshee.Base
         
         public void Remove(ICollection tracks)
         {
-            string query = "DELETE FROM Tracks WHERE ";
+            string query_tracks = "DELETE FROM Tracks WHERE ";
+            string query_track_licenses = "DELETE FROM TrackLicenses WHERE ";
             int remove_count = 0;
             int invalid_count = 0;
             
@@ -251,9 +258,14 @@ namespace Banshee.Base
                     continue;
                 }
 
-                query += String.Format(" TrackID = '{0}' ", track.TrackId);
+                query_tracks += String.Format(" TrackID = '{0}' ", track.TrackId);
+                if(remove_count < tracks.Count - invalid_count - 1) {
+                    query_tracks += " OR ";
+                }
+                
+                query_track_licenses += String.Format(" TrackID = '{0}' ", track.TrackId);
                 if(remove_count < tracks.Count - invalid_count - 1) {
-                    query += " OR ";
+                    query_track_licenses += " OR ";
                 }
                 
                 CollectionRemove(track);
@@ -261,7 +273,8 @@ namespace Banshee.Base
             }
             
             if(remove_count > 0) {
-                Db.Execute(query);
+                Db.Execute(query_tracks);
+                Db.Execute(query_track_licenses);
                             
                 LibraryTrackRemovedHandler removed_handler = TrackRemoved;
                 if(removed_handler != null) {
Index: src/Banshee.Base/LibraryTrackInfo.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/LibraryTrackInfo.cs,v
retrieving revision 1.13
diff -u -p -r1.13 LibraryTrackInfo.cs
--- src/Banshee.Base/LibraryTrackInfo.cs	28 Jul 2006 02:32:12 -0000	1.13
+++ src/Banshee.Base/LibraryTrackInfo.cs	6 Aug 2006 16:55:06 -0000
@@ -157,8 +157,10 @@ namespace Banshee.Base
         }
 
         public LibraryTrackInfo(SafeUri uri, string artist, string album, 
-           string title, string genre, uint track_number, uint track_count,
-           int year, TimeSpan duration, string asin, RemoteLookupStatus remote_lookup_status)
+           string title, string genre, Licenses.Attributes license,
+           string copyright, string license_uri, string metadata_uri, uint track_number,
+           uint track_count, int year, TimeSpan duration, string asin,
+           RemoteLookupStatus remote_lookup_status, LicenseVerifyStatus license_verify_status)
         {
             this.uri = uri;
             track_id = 0;
@@ -169,12 +171,20 @@ namespace Banshee.Base
             this.album = album;
             this.title = title;
             this.genre = genre;
+            
+            this.license = license;
+            this.copyright = copyright;
+            this.license_uri = license_uri;
+            this.metadata_uri = metadata_uri;
+            
             this.track_number = track_number;
             this.track_count = track_count;
             this.year = year;
             this.duration = duration;
             this.asin = asin;
+            
             this.remote_lookup_status = remote_lookup_status;
+            this.license_verify_status = license_verify_status;
             
             this.date_added = DateTime.Now;
             
@@ -188,8 +198,9 @@ namespace Banshee.Base
         
         public LibraryTrackInfo(SafeUri uri, TrackInfo track) : this(
             uri, track.Artist, track.Album, track.Title, track.Genre,
+            track.License, track.Copyright, track.LicenseUri, track.MetadataUri,
             track.TrackNumber, track.TrackCount, track.Year, track.Duration, 
-            track.Asin, track.RemoteLookupStatus)
+            track.Asin, track.RemoteLookupStatus, track.LicenseVerifyStatus)
         {
         }
     
@@ -204,9 +215,9 @@ namespace Banshee.Base
                 CheckIfExists(uri);
                 SaveToDatabase(true);
             }
-
+            
             Globals.Library.SetTrack(track_id, this);
-
+            
             PreviousTrack = Gtk.TreeIter.Zero;
         }
         
@@ -287,7 +298,8 @@ namespace Banshee.Base
         private void SaveToDatabase(bool retryIfFail)
         {
             Statement tracksQuery;
-
+            Statement trackLicensesQuery;
+            
 //            Console.WriteLine ("{0} has id {1}", uri.LocalPath, TrackId);
 
             if(track_id <= 0) {
@@ -315,6 +327,14 @@ namespace Banshee.Base
                     "NumberOfPlays", play_count, 
                     "LastPlayedStamp", DateTimeUtil.FromDateTime(last_played),
                     "RemoteLookupStatus", (int)remote_lookup_status);
+                
+                trackLicensesQuery = new Insert("TrackLicenses", true,
+                    "TrackID", null, 
+                    "License", (int)license,
+                    "Copyright", copyright,
+                    "LicenseURI", license_uri,
+                    "MetadataURI", metadata_uri,
+                    "LicenseVerifyStatus", (int)license_verify_status);
             } else {
                 tracksQuery = new Update("Tracks",
                     "Uri", uri.AbsoluteUri,
@@ -340,15 +360,24 @@ namespace Banshee.Base
                     "LastPlayedStamp", DateTimeUtil.FromDateTime(last_played),
                     "RemoteLookupStatus", (int)remote_lookup_status) +
                     new Where(new Compare("TrackID", Op.EqualTo, track_id));// +
-                //    new Limit(1);
+                    //    new Limit(1);
+                
+                trackLicensesQuery = new Update("TrackLicenses",
+                    "License", (int)license,
+                    "Copyright", copyright,
+                    "LicenseURI", license_uri,
+                    "MetadataURI", metadata_uri,
+                    "LicenseVerifyStatus", (int)license_verify_status) +
+                    new Where(new Compare("TrackID", Op.EqualTo, track_id));
             }
             
             try {
                 Globals.Library.Db.Execute(tracksQuery);
+                Globals.Library.Db.Execute(trackLicensesQuery);
             } catch(Exception e) {
                 Console.WriteLine(e);
             }
-
+            
             /*if(Core.Library.Db.Execute(query) <= 0 && retryIfFail) {
                 track_id = 0;
                 SaveToDatabase(false);
@@ -384,6 +413,25 @@ namespace Banshee.Base
         private void LoadFromDatabaseReader(IDataReader reader)
         {
             track_id = Convert.ToInt32(reader["TrackID"]);
+            
+            string query = String.Format(@"
+                SELECT * 
+                FROM TrackLicenses
+                WHERE TrackID = '{0}'
+                LIMIT 1", track_id
+            );
+            
+            IDataReader license_reader = Globals.Library.Db.Query(query);
+
+            if(license_reader != null && license_reader.Read()) {
+                license = (Licenses.Attributes)Convert.ToInt32(
+                                            license_reader["License"]);
+                copyright = license_reader["Copyright"] as string;
+                license_uri = license_reader["LicenseURI"] as string;
+                metadata_uri = license_reader["MetadataURI"] as string;
+                license_verify_status = (LicenseVerifyStatus)Convert.ToInt32(
+                                            license_reader["LicenseVerifyStatus"]);
+            }
 
             uri = new SafeUri(reader["Uri"] as string, true);
             mimetype = reader["MimeType"] as string;
Index: src/Banshee.Base/Makefile.am
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Makefile.am,v
retrieving revision 1.48
diff -u -p -r1.48 Makefile.am
--- src/Banshee.Base/Makefile.am	5 Aug 2006 21:35:57 -0000	1.48
+++ src/Banshee.Base/Makefile.am	6 Aug 2006 16:55:06 -0000
@@ -90,6 +90,7 @@ GUI_SOURCES = \
 	$(srcdir)/Gui/LogCoreDialog.cs \
 	$(srcdir)/Gui/VersionInformationDialog.cs \
 	$(srcdir)/Gui/ToggleStates.cs \
+	$(srcdir)/Gui/LicenseRenderer.cs \
 	$(srcdir)/Gui/RatingRenderer.cs
 
 AUDIOCD_SOURCES = \
@@ -200,6 +201,7 @@ ASSEMBLY_SOURCES = \
 	$(srcdir)/BansheeBranding.cs \
 	$(srcdir)/ComponentInitializer.cs \
 	$(srcdir)/PowerManagement.cs \
+	$(srcdir)/Licenses.cs \
 	$(srcdir)/ProductInformation.cs
 
 Banshee_Base_RESOURCES = \
@@ -215,6 +217,22 @@ Banshee_Base_RESOURCES = \
 	data/images/media-playlist-continuous.png \
 	data/images/star.png \
 	data/images/circle.png \
+	data/images/cc-by_nc_nd.png \
+    data/images/cc-by_nc.png \
+    data/images/cc-by_nc_sa.png \
+    data/images/cc-by_nd.png \
+    data/images/cc-by.png \
+    data/images/cc-by_sa.png \
+    data/images/cc-devnations.png \
+    data/images/cc-nc.png \
+    data/images/cc-nc_samplingplus.png \
+    data/images/cc-nc_sa.png \
+    data/images/cc-nd_nc.png \
+    data/images/cc-nd.png \
+    data/images/cc-publicdomain.png \
+    data/images/cc-samplingplus.png \
+    data/images/cc-sampling.png \
+    data/images/cc-sa.png \
 	COPYING
 
 Banshee_Base_EXPANDED_RESOURCES = $(foreach resource,$(Banshee_Base_RESOURCES), $(top_srcdir)/$(resource))
Index: src/Banshee.Base/StreamTagger.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/StreamTagger.cs,v
retrieving revision 1.2
diff -u -p -r1.2 StreamTagger.cs
--- src/Banshee.Base/StreamTagger.cs	14 May 2006 03:22:46 -0000	1.2
+++ src/Banshee.Base/StreamTagger.cs	6 Aug 2006 16:55:07 -0000
@@ -66,6 +66,10 @@ namespace Banshee.Base
                     case CommonTags.Genre:
                         track.Genre = Choose((string)tag.Value, track.Genre);
                         break;
+                    case CommonTags.Copyright:
+                        track.Copyright = Choose((string)tag.Value, track.Copyright);
+                        Licenses.FillTags(track);
+                        break;
                     case CommonTags.TrackNumber:
                         uint track_number = (uint)tag.Value;
                         track.TrackNumber = track_number == 0 ? track.TrackNumber : track_number;
Index: src/Banshee.Base/TrackInfo.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/TrackInfo.cs,v
retrieving revision 1.14
diff -u -p -r1.14 TrackInfo.cs
--- src/Banshee.Base/TrackInfo.cs	6 Jul 2006 19:32:34 -0000	1.14
+++ src/Banshee.Base/TrackInfo.cs	6 Aug 2006 16:55:07 -0000
@@ -39,6 +39,12 @@ namespace Banshee.Base
         Failure
     }
     
+    public enum LicenseVerifyStatus {
+        NoAttempt = 0,
+        Valid,
+        Invalid
+    }
+    
     public class HaveTrackInfoArgs : EventArgs
     {
         public TrackInfo TrackInfo;
@@ -58,6 +64,11 @@ namespace Banshee.Base
         protected string genre;
         protected string performer;
 
+        protected Licenses.Attributes license = Licenses.Attributes.none;   // None if unverified
+        protected string copyright;     // License and Verification URIs (TCOP)
+        protected string license_uri;   // License URI (WCOP)
+        protected string metadata_uri;  // Metadata verification URI (WOAF)
+
         protected string asin;
         protected string label;
 
@@ -78,6 +89,7 @@ namespace Banshee.Base
         protected bool can_save_to_database;
         protected bool can_play = true;
         protected RemoteLookupStatus remote_lookup_status = RemoteLookupStatus.NoAttempt;
+        protected LicenseVerifyStatus license_verify_status = LicenseVerifyStatus.NoAttempt;
 
         public Gtk.TreeIter PreviousTrack;
         public Gtk.TreeIter TreeIter;
@@ -163,6 +175,16 @@ namespace Banshee.Base
             }
         }
         
+        public LicenseVerifyStatus LicenseVerifyStatus {
+            get {
+                return license_verify_status;
+            }
+            
+            set {
+                license_verify_status = value;
+            }
+        }
+        
         protected string cover_art_file = null;
         public string CoverArtFileName { 
             get {
@@ -257,6 +279,50 @@ namespace Banshee.Base
             } 
         }
 
+        public Licenses.Attributes License {
+            get {
+                return license;
+            }
+
+            set {
+                license = value;
+                WriteUpdate();
+            }
+        }
+
+        public string Copyright { 
+            get { 
+                return copyright;
+            }
+
+            set { 
+                copyright = value;
+                WriteUpdate();
+            } 
+        }
+
+        public string LicenseUri { 
+            get { 
+                return license_uri;
+            }
+
+            set { 
+                license_uri = value;
+                WriteUpdate();
+            } 
+        }
+
+        public string MetadataUri {
+            get {
+                return metadata_uri;
+            }
+
+            set {
+                metadata_uri = value;
+                WriteUpdate();
+            }
+        }
+
         [BansheeTodo("Completely unused, should we even have this?")]
         public string Performer {
             get { 
0a1,126
--- /dev/null	2006-05-22 10:25:23.000000000 -0400
+++ src/Banshee.Base/Licenses.cs	2006-08-06 01:23:31.000000000 -0400
@@ -0,0 +1,126 @@
+/***************************************************************************
+ *  Licenses.cs
+ *
+ *  Copyright (C) 2006 Luke Hoersten
+ *  Written by Luke Hoersten <luke.hoersten@gmail.com>
+ ****************************************************************************/
+
+/*  THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: 
+ *
+ *  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.Collections.Generic;
+
+namespace Banshee.Base
+{
+	public static class Licenses
+	{
+	    public enum Attributes {
+            none = 0,
+            nd,
+            nd_nc,
+            nc,
+            nc_sa,
+            sa,
+            by,
+            by_nd,
+            by_nc,
+            by_nc_nd,
+            by_nc_sa,
+            by_sa,
+            sampling,
+            samplingplus,
+            nc_samplingplus,
+            devnations,
+            publicdomain
+	    }
+	    
+	    private static string HTTP_STRING = "http://";
+	    private static string LICENSES_STRING = "licenses/";
+        private static int    LICENSES_LENGTH = 9;
+	    private static string VERIFY_STRING = "verify at ";
+        private static int    VERIFY_LENGTH = 10;
+	    
+        public static void FillTags(TrackInfo track)
+        {
+            if(track.Copyright == null) {
+                    return;
+            } else {
+                if(track.LicenseUri == null && track.MetadataUri == null) {
+                    try {
+                        track.LicenseUri = ParseLicenseUri(track.Copyright);
+                        track.MetadataUri = ParseMetadataUri(track.Copyright);
+                    } catch(LicenseParseException) {
+                        return;
+                    }
+                }
+            }
+            
+            track.License = (Attributes)Enum.Parse(typeof(Attributes),
+                                ParseAttributes(track.LicenseUri).Replace("-", "_").Replace("+", "plus"));
+        }
+        
+        private static string ParseAttributes(string data)
+        {
+            int licenses_index = data.ToLower().IndexOf(LICENSES_STRING);
+            if(licenses_index <= 0) {
+                throw new LicenseParseException("No attributes were found in Copyright tag.");
+            }
+            
+            int attribute_index = licenses_index + LICENSES_LENGTH;
+            return data.Substring(attribute_index, data.IndexOf('/', attribute_index) - attribute_index);
+        }
+
+        private static string ParseLicenseUri(string data)
+        {
+            int verify_index = (data.ToLower()).IndexOf(VERIFY_STRING);
+            if(verify_index <= 0) {
+                throw new LicenseParseException("No metadata was found in Copyright tag while parsing license URL.");    
+            }
+            
+            int http_index = (data.ToLower()).LastIndexOf(HTTP_STRING, verify_index);
+            if(http_index <= 0) {
+                throw new LicenseParseException("No license was found in Copyright tag.");
+            }
+            
+            /* The -1 is because LastIndexOf adds 1 for arg test */
+            return data.Substring(http_index, (verify_index - http_index) - 1);
+        }
+
+        private static string ParseMetadataUri(string data)
+        {
+            int verify_index = data.ToLower().IndexOf(VERIFY_STRING);
+            if(verify_index <= 0) {
+                throw new LicenseParseException("No metadata was found in Copyright tag at parsing metadata URL.");
+            }
+            
+            int metadata_index = verify_index + VERIFY_LENGTH;
+            return data.Substring(metadata_index, data.Length - (metadata_index));
+        }
+	}
+	                
+    public class LicenseParseException : ApplicationException
+    {
+        public LicenseParseException(string m) : base(m)
+        {
+        }
+    }
+}
--- /dev/null	2006-05-22 10:25:23.000000000 -0400
+++ src/Banshee.Base/Gui/LicenseRenderer.cs	2006-08-06 12:12:53.000000000 -0400
@@ -0,0 +1,119 @@
+/***************************************************************************
+ *  LicenseRenderer.cs
+ *
+ *  Copyright (C) 2006 Luke Hoersten
+ *  Written by Luke Hoersten <luke.hoersten@gmail.com>
+ ****************************************************************************/
+
+/*  THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: 
+ *
+ *  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 Gtk;
+using Gdk;
+
+using Banshee.Base;
+
+namespace Banshee.Gui
+{
+	public class LicenseRenderer : CellRenderer
+	{
+	    public TrackInfo Track;
+        private static Gdk.Pixbuf[] icon_lookup;
+		
+		public LicenseRenderer()
+		{
+		    if(icon_lookup == null)
+		        LoadIcons();
+		}
+
+		protected LicenseRenderer(System.IntPtr ptr) : base(ptr)
+		{
+		    if(icon_lookup == null)
+		        LoadIcons();
+		}
+        
+        private void LoadIcons() {
+            System.Array values = System.Enum.GetValues(typeof(Licenses.Attributes));
+            icon_lookup = new Gdk.Pixbuf[values.Length];
+            
+            foreach(Licenses.Attributes la in values) {
+                if(la != Licenses.Attributes.none)
+                    icon_lookup[(int)la] = Gdk.Pixbuf.LoadFromResource("cc-" + la.ToString() + ".png");
+            }
+        }
+        
+		private StateType RendererStateToWidgetState(CellRendererState flags)
+		{
+		    StateType state = StateType.Normal;
+			
+			if((CellRendererState.Insensitive & flags).Equals(
+				CellRendererState.Insensitive)) {
+				state = StateType.Insensitive;
+			} else if((CellRendererState.Selected & flags).Equals( 
+				CellRendererState.Selected)) {
+				state = StateType.Selected;
+			}
+			
+			return state;
+		}
+		
+		protected override void Render(Gdk.Drawable drawable, 
+			Widget widget, Gdk.Rectangle background_area, 
+			Gdk.Rectangle cell_area, Gdk.Rectangle expose_area, 
+			CellRendererState flags)
+		{
+			Gdk.Window window = drawable as Gdk.Window;
+			StateType state = RendererStateToWidgetState(flags);
+			
+			DrawLicense(window, widget, cell_area, state, flags);
+		}
+		
+		public override void GetSize(Widget widget, ref Gdk.Rectangle cell_area, 
+			out int x_offset, out int y_offset, out int width, out int height)
+		{
+		    height = icon_lookup[(int)Licenses.Attributes.nd].Height + 2;
+		    width = (icon_lookup[(int)Licenses.Attributes.nd].Width * 3) + 4;
+		    x_offset = 0;
+		    y_offset = 0;
+		}
+	
+		private void DrawLicense(Gdk.Window canvas, Gtk.Widget widget,
+			Gdk.Rectangle area, StateType state, CellRendererState flags)
+		{
+		    if(!ShowLicense(Track))
+		        return;
+    
+			canvas.DrawPixbuf(widget.Style.TextGC(state), icon_lookup[(int)Track.License], 0, 0,
+               area.X + 2, area.Y + 1, icon_lookup[(int)Track.License].Width,
+               icon_lookup[(int)Track.License].Height, RgbDither.None, 0, 0);
+		}
+		
+		public bool ShowLicense(TrackInfo track)
+        {
+            if(track.License == Licenses.Attributes.none) // No License
+		        return false;
+		    else if(track.LicenseVerifyStatus == LicenseVerifyStatus.Invalid) // Invalid License
+		        return false;
+		    else
+		        return true;
+        }
+	}
+}
