Index: gsd-housekeeping-manager.c
===================================================================
--- gsd-housekeeping-manager.c	(revision 236)
+++ gsd-housekeeping-manager.c	(working copy)
@@ -39,9 +39,17 @@
 #define DEFAULT_MAX_AGE_IN_DAYS 60
 #define GCONF_THUMB_SIZE "/desktop/gnome/thumbnail_cache/maximum_size"
 #define DEFAULT_MAX_SIZE_IN_MB 64
-#define GCONF_THUMB_BINDING_DIR "/desktop/gnome/thumbnail_cache" 
+#define GCONF_THUMB_BINDING_DIR "/desktop/gnome/thumbnail_cache"
 
 
+/* .recently-used.xbel cleaner */
+
+#define GCONF_RECENTLY_USED_AGE "/desktop/gnome/recently_used/max_age"
+#define DEFAULT_RECENTLY_USED_AGE_IN_DAYS 90
+#define GCONF_RECENTLY_USED_COUNT "/desktop/gnome/recently_used/max_per_mime_type"
+#define DEFAULT_RECENTLY_USED_COUNT 32
+#define GCONF_RECENTLY_USED_BINDING_DIR "/desktop/gnome/recently_used"
+
 struct GsdHousekeepingManagerPrivate {
         gint long_term_cb;
         gint short_term_cb;
@@ -85,6 +93,26 @@
 }
 
 
+typedef struct {
+        char    *uri;
+        char    *mime_type;
+        time_t   visited;
+        gboolean valid;
+} BookmarkData;
+
+
+static void
+bookmark_data_free (gpointer data)
+{
+        BookmarkData *bm_data = data;
+
+        if (bm_data) {
+                g_free (bm_data->uri);
+                g_free (bm_data->mime_type);
+        }
+}
+
+
 static GList *
 read_dir_for_purge (const char *path, GList *files)
 {
@@ -240,10 +268,134 @@
 }
 
 
+static int
+sort_by_visited (BookmarkData *bm1, BookmarkData *bm2)
+{
+        return bm1->visited - bm2->visited;
+}
+
+
+static void
+purge_recently_used_xbel (void)
+{
+        GList         *bookmarks = NULL;
+        GTimeVal       current_time;
+        char         **uris;
+        char          *filename;
+        int            max_per_type;
+        int            max_age;
+        int            i;
+        GBookmarkFile *bm_file;
+        GHashTable    *mime_types;
+
+        g_debug ("housekeeping: checking recently-used bookmark file size and freshness");
+
+        max_age = get_gconf_int_with_nonzero_default (GCONF_RECENTLY_USED_AGE,
+                        DEFAULT_RECENTLY_USED_AGE_IN_DAYS * 24 * 60 * 60);
+        max_per_type = get_gconf_int_with_nonzero_default (GCONF_RECENTLY_USED_COUNT,
+                        DEFAULT_RECENTLY_USED_COUNT);
+
+        if ((max_per_type < 0) && (max_age < 0))
+                return;
+
+        g_get_current_time (&current_time);
+
+        bm_file = g_bookmark_file_new ();
+        filename = g_build_filename (g_get_home_dir (),
+                                     ".recently-used.xbel",
+                                     NULL);
+        if (!g_bookmark_file_load_from_file (bm_file, filename, NULL)) {
+                g_bookmark_file_free (bm_file);
+                g_free (filename);
+                return;
+        }
+
+        mime_types = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+        uris = g_bookmark_file_get_uris (bm_file, NULL);
+
+        for (i = 0; uris[i]; i++) {
+                BookmarkData *bookmark_data;
+                gpointer      count;
+
+                /* Save list of URIs for sorting and purging */
+                bookmark_data = g_new (BookmarkData, 1);
+                bookmark_data->uri = g_strdup (uris[i]);
+                bookmark_data->visited = g_bookmark_file_get_visited (bm_file, uris[i], NULL);
+                bookmark_data->valid = TRUE;
+
+                bookmark_data->mime_type = g_strdup (g_bookmark_file_get_mime_type (bm_file, uris[i], NULL));
+                if (bookmark_data->mime_type == NULL)
+                        bookmark_data->mime_type = g_strdup ("none");
+
+                if (((current_time.tv_sec - bookmark_data->visited) > max_age) &&
+                                (max_age >= 0)) {
+                        bookmark_data->valid = FALSE;
+                }
+
+                if (bookmark_data->valid == TRUE) {
+                        /* Does the URI still exist? */
+                        GFile *file;
+                        file = g_file_new_for_uri (bookmark_data->uri);
+                        bookmark_data->valid = g_file_query_exists (file, NULL);
+                        g_object_unref (file);
+                }
+
+                if (bookmark_data->valid == FALSE) {
+                        g_bookmark_file_remove_item (bm_file, uris[i], NULL);
+                } else {
+                        bookmarks = g_list_prepend (bookmarks, bookmark_data);
+
+                        /* Count number of files of each mime type */
+                        count = g_hash_table_lookup (mime_types, bookmark_data->mime_type);
+                        if (count) {
+                                g_hash_table_insert (mime_types,
+                                                     g_strdup (bookmark_data->mime_type),
+                                                     GINT_TO_POINTER (GPOINTER_TO_INT (count) + 1));
+                        } else {
+                                g_hash_table_insert (mime_types,
+                                                     g_strdup (bookmark_data->mime_type),
+                                                     GINT_TO_POINTER (1));
+                        }
+                }
+        }
+
+        g_strfreev (uris);
+
+        if (max_per_type >= 0) {
+                GList *scan;
+                bookmarks = g_list_sort (bookmarks, (GCompareFunc) sort_by_visited);
+                for (scan = bookmarks; scan; scan = scan->next) {
+                        int count;
+                        BookmarkData *bookmark_data = scan->data;
+
+                        count = GPOINTER_TO_INT (g_hash_table_lookup (mime_types, bookmark_data->mime_type));
+
+                        if (count > max_per_type) {
+                                g_bookmark_file_remove_item (bm_file, bookmark_data->uri, NULL);
+                                g_hash_table_insert (mime_types,
+                                                     g_strdup (bookmark_data->mime_type),
+                                                     GINT_TO_POINTER (count - 1));
+                        }
+                }
+        }
+
+        g_bookmark_file_to_file (bm_file, filename, NULL);
+        g_bookmark_file_free (bm_file);
+        g_free (filename);
+
+        g_list_foreach (bookmarks, (GFunc) bookmark_data_free, NULL);
+        g_list_free (bookmarks);
+
+        g_hash_table_destroy (mime_types);
+}
+
+
 static gboolean
 do_cleanup (GsdHousekeepingManager *manager)
 {
         purge_thumbnail_cache ();
+        purge_recently_used_xbel ();
         return TRUE;
 }
 
@@ -306,6 +458,10 @@
                                   GCONF_THUMB_BINDING_DIR,
                                   (GConfClientNotifyFunc) bindings_callback);
 
+        register_config_callback (manager,
+                                  GCONF_RECENTLY_USED_BINDING_DIR,
+                                  (GConfClientNotifyFunc) bindings_callback);
+
         /* Clean once, a few minutes after start-up */
         do_cleanup_soon (manager);
 
