diff -urNpX dontdiff beagle-orig/BeagleClient/RemoteControl.cs beagle/BeagleClient/RemoteControl.cs
--- beagle-orig/BeagleClient/RemoteControl.cs	2005-03-26 23:51:03.000000000 +0000
+++ beagle/BeagleClient/RemoteControl.cs	2005-03-31 08:33:46.000000000 +0100
@@ -68,5 +68,10 @@ namespace Beagle {
 		{
 			return TheProxy.GetIndexInformation ();
 		}
+
+		public static void ReloadConfig ()
+		{
+			TheProxy.ReloadConfig ();
+		}
 	}
 }
diff -urNpX dontdiff beagle-orig/BeagleClient/RemoteControlProxy.cs beagle/BeagleClient/RemoteControlProxy.cs
--- beagle-orig/BeagleClient/RemoteControlProxy.cs	2005-03-26 23:51:03.000000000 +0000
+++ beagle/BeagleClient/RemoteControlProxy.cs	2005-03-31 08:33:56.000000000 +0100
@@ -42,6 +42,9 @@ namespace Beagle
 
 		[Method]
 		public abstract string GetIndexInformation ();
+
+		[Method]
+		public abstract void ReloadConfig ();
 	}
 }
-	
+
diff -urNpX dontdiff beagle-orig/beagled/BeagleDaemon.cs beagle/beagled/BeagleDaemon.cs
--- beagle-orig/beagled/BeagleDaemon.cs	2005-03-26 23:51:11.000000000 +0000
+++ beagle/beagled/BeagleDaemon.cs	2005-03-28 16:55:35.000000000 +0100
@@ -457,6 +457,9 @@ namespace Beagle.Daemon {
 			// warning if not.  The actual advice calls will fail silently.
 			FileAdvise.TestAdvise ();
 
+			// Parse config file
+			Conf.Load ();
+
 			Shutdown.ShutdownEvent += OnShutdown;
 
 			stopwatch.Stop ();
diff -urNpX dontdiff beagle-orig/beagled/FileSystemQueryable/FileNameFilter.cs beagle/beagled/FileSystemQueryable/FileNameFilter.cs
--- beagle-orig/beagled/FileSystemQueryable/FileNameFilter.cs	2005-03-26 23:51:12.000000000 +0000
+++ beagle/beagled/FileSystemQueryable/FileNameFilter.cs	2005-03-29 18:11:14.000000000 +0100
@@ -1,4 +1,3 @@
-//
 // FileNameFilter.cs
 //
 // Copyright (C) 2004 Novell, Inc.
@@ -36,12 +35,18 @@ namespace Beagle.Daemon.FileSystemQuerya
 	public class FileNameFilter {
 		
 		static string home_dir;
+		private FileSystemModel model = null;
+		private ArrayList patternsToIgnore = null;
 
 		static FileNameFilter ()
 		{
 			home_dir = PathFinder.HomeDir;
 		}
 
+		public FileNameFilter (FileSystemModel model) : this ()
+		{
+			this.model = model;
+		}
 
 		private class Pattern {
 			private string exactMatch;
@@ -96,180 +101,28 @@ namespace Beagle.Daemon.FileSystemQuerya
 			}
 		}
 
-		static ArrayList LoadPatterns (string filename)
-		{
-			if (! File.Exists (filename))
-				return null;
-			
-			ArrayList array = new ArrayList ();
-			StreamReader sr = new StreamReader (filename);
-			string line;
-			while ((line = sr.ReadLine ()) != null) {
-				line = line.Trim ();
-				if (line.Length > 0) {
-					Pattern pattern = new Pattern (line);
-					array.Add (pattern);
-				}
-			}
-			
-			return array;
-		}
-
 		//////////////////////////////////////////////////////////////////////
-		
-		private ArrayList defaultPatternsToIgnore;
 
-		private void SetupDefaultPatternsToIgnore ()
+		public void AddPatternToIgnore (string pattern)
 		{
-			defaultPatternsToIgnore = new ArrayList ();
-
-			// Add our default skip patterns.
-			// FIXME: This probably shouldn't be hard-wired.  Or should it?
-			AddDefaultPatternToIgnore (".*",
-						   "*~",
-						   "#*#",
-						   "*.o",
-						   "*.a",
-						   "*.S",
-						   "*.la",
-						   "*.lo",
-						   "*.loT",
-						   "*.so",
-						   "*.exe",
-						   "*.dll",
-						   "*.mdb",
-						   "*.com",
-						   "*.csproj",
-						   "*.dsp",
-						   "*.dsw",
-						   "*.m4",
-						   "*.pc",
-						   "*.pc.in",
-						   "*.in.in",
-						   "*.omf",
-						   "*.aux",
-						   "*.tmp",
-						   "autom4te.cache",
-						   "po",
-						   "aclocal",
-						   "Makefile",
-						   "Makefile.am",
-						   "Makefile.in",
-						   "CVS",
-						   // Garbage generated by the autotools
-						   "conftest",
-						   "confdefs.h",
-						   "conftest.*",
-						   "confstat*",
-						   "/conf[0-9]+.sh/",
-						   "/conf[0-9]+.file/"
-				);
-			
-			// Read the ~/.neverindex file, which contains patterns
-			// for files that should always be ignored.
-			string neverindex = Path.Combine (home_dir, ".neverindex");
-			ArrayList patterns = LoadPatterns (neverindex);
-			if (patterns != null) {
-				foreach (Pattern pattern in patterns)
-					defaultPatternsToIgnore.Add (pattern);
-			}
+			patternsToIgnore.Add (new Pattern (pattern));
 		}
 
-		public void AddDefaultPatternToIgnore (string pattern)
-		{
-			defaultPatternsToIgnore.Add (new Pattern (pattern));
-		}
-		
-		public void AddDefaultPatternToIgnore (params string[] patterns)
+		public void AddPatternToIgnore (IList patterns)
 		{
 			foreach (string pattern in patterns)
-				AddDefaultPatternToIgnore (pattern);
+				AddPatternToIgnore (pattern);
 		}
 		
 		/////////////////////////////////////////////////////////////
 
 		public FileNameFilter ()
 		{
-			SetupDefaultPatternsToIgnore ();
+			patternsToIgnore = new ArrayList ();
 		}
 
 		/////////////////////////////////////////////////////////////
 
-		private class PerDirectoryInfo {
-			string dir;
-			DateTime noindexTimestamp;
-			DateTime noindexLastCheck;
-			ArrayList patternsToIgnore;
-
-			public PerDirectoryInfo (string _dir)
-			{
-				dir = _dir;
-				ConditionallyLoad ();
-			}
-
-			public bool IsEmpty {
-				get { return patternsToIgnore == null; }
-			}
-
-			// If the directory's .noindex file has changed, load it.
-			// FIXME: This should be done with inotify instead of using
-			// this sort of seek-happy polling.
-			private void ConditionallyLoad ()
-			{
-				// Only re-check the .noindex file every 11 seconds.
-				DateTime now = DateTime.Now;
-				if ((now - noindexLastCheck).TotalSeconds < 11)
-					return;
-				noindexLastCheck = now;
-
-				string noindex = Path.Combine (dir, ".noindex");
-
-				if (File.Exists (noindex)) {
-					DateTime timestamp = File.GetLastWriteTime (noindex);
-					if (timestamp != noindexTimestamp) {
-						patternsToIgnore = LoadPatterns (noindex);
-						noindexTimestamp = timestamp;
-					}
-				} else {
-					patternsToIgnore = null;
-				}
-			}
-
-			public bool Ignore (string name)
-			{
-				ConditionallyLoad ();
-				if (patternsToIgnore == null)
-					return false;
-				if (patternsToIgnore.Count == 0) // i.e. IgnoreAll
-					return true;
-				foreach (Pattern pattern in patternsToIgnore)
-					if (pattern.IsMatch (name))
-						return true;
-
-				return false;
-			}
-		}
-
-		
-		private Hashtable perDirectoryCache = new Hashtable ();
-
-		private PerDirectoryInfo GetPerDirectoryInfo (string dir)
-		{
-			if (dir == null)
-				return null;
-
-			// Only cache the non-trivial per-directory information
-			PerDirectoryInfo info;
-			lock (perDirectoryCache) {
-				if (! perDirectoryCache.Contains (dir)) {
-					info = new PerDirectoryInfo (dir);
-					perDirectoryCache [dir] = info.IsEmpty ? null : info;
-				}
-				info = perDirectoryCache [dir] as PerDirectoryInfo;
-			}
-			return info;
-		}
-
 		// FIXME: We could make this more efficient by storing more information.
 		// In particular, if ~/foo is an IgnoreAll directory, we could store
 		// that info in the PerDirectoryInfo of subdir ~/foo/bar so that
@@ -279,22 +132,18 @@ namespace Beagle.Daemon.FileSystemQuerya
 			if (! Path.IsPathRooted (path))
 				path = Path.GetFullPath (path);
 			
-			if (path == home_dir)
-				return false;
+			foreach (FileSystemModel.Directory root in model.Roots)
+				if (root.FullName == path)
+					return false;
 
 			string name = Path.GetFileName (path);
 
-			foreach (Pattern pattern in defaultPatternsToIgnore) {
+			foreach (Pattern pattern in patternsToIgnore)
 				if (pattern.IsMatch (name))
 					return true;
-			}
 
 			string dir = Path.GetDirectoryName (path);
-			PerDirectoryInfo perDir = GetPerDirectoryInfo (dir);
 
-			if (perDir != null && perDir.Ignore (name))
-				return true;
-			
 			// A file should be ignored if any of its parent directories
 			// is ignored.
 			return Ignore (dir);
diff -urNpX dontdiff beagle-orig/beagled/FileSystemQueryable/FileSystemModel.cs beagle/beagled/FileSystemQueryable/FileSystemModel.cs
--- beagle-orig/beagled/FileSystemQueryable/FileSystemModel.cs	2005-03-26 23:51:12.000000000 +0000
+++ beagle/beagled/FileSystemQueryable/FileSystemModel.cs	2005-03-29 18:13:41.000000000 +0100
@@ -414,12 +414,12 @@ namespace Beagle.Daemon.FileSystemQuerya
 		Hashtable path_cache = new Hashtable ();
 		Hashtable by_unique_id = new Hashtable ();
 		Queue to_be_scanned = new Queue ();
-		FileNameFilter filter = new FileNameFilter ();
 
 		IFileEventBackend event_backend;
 		int needs_crawl_count = 0;
 		int block_activity = 0;
 
+		FileNameFilter filter;
 		UniqueIdStore unique_id_store;
 		NameIndex name_index;
 		FileAttributesStore backing_store;
@@ -434,6 +434,7 @@ namespace Beagle.Daemon.FileSystemQuerya
 
 			unique_id_store = new UniqueIdStore (index_directory, index_fingerprint);
 			name_index = new NameIndex (index_directory, index_fingerprint);
+			filter = new FileNameFilter (this);
 
 			IFileAttributesStore backing_store_i;
 			backing_store_i = new FileAttributesStore_Mixed (index_directory, index_fingerprint);
@@ -461,6 +462,42 @@ namespace Beagle.Daemon.FileSystemQuerya
 			get { lock (big_lock) return roots.Clone () as ArrayList; }
 		}
 
+		public void LoadConf ()
+		{
+			// FIXME: We need to check that we aren't adding duplicates
+			filter.AddPatternToIgnore (Conf.Indexing.IgnorePatterns);
+			// FIXME: We need to remove patterns which are no longer ignored
+
+			// Remove roots which are no longer required
+			// FIXME : Trailing slashes etc.
+			// FIXME : Is this loop safe? (loop around elements in a list while deleting some)
+			foreach (Directory root in roots) {
+				string path = root.FullName;
+				if (! Conf.Indexing.Roots.Contains (path)
+						&& (path == PathFinder.HomeDir
+							&& ! Conf.Indexing.SpecialRoots.Contains ("homedir")))
+					DelRoot (path);
+			}
+
+			// Add new roots
+			foreach (string root in Conf.Indexing.Roots)
+				AddRoot (root);
+
+			foreach (string special in Conf.Indexing.SpecialRoots) {
+				string root;
+
+				switch (special) {
+				case "homedir":
+					root = PathFinder.HomeDir;
+					break;
+				default:
+					continue;
+				}
+
+				AddRoot (root);
+			}
+		}
+
 		public Directory AddRoot (string path)
 		{
 			// Remove trailing directory separators, which cause Path.FileName
@@ -471,7 +508,9 @@ namespace Beagle.Daemon.FileSystemQuerya
 				path = path.Substring (0, path.Length-1);
 
 			Logger.Log.Debug ("Adding root {0}", path);
-				
+			
+//FIXME check that root exists (above)
+			
 			DirectoryPrivate root = new DirectoryPrivate (big_lock);
 			root.InitRoot (System.IO.Path.GetDirectoryName (path), 
 				       System.IO.Path.GetFileName (path));
@@ -487,7 +526,7 @@ namespace Beagle.Daemon.FileSystemQuerya
 				// of any existing root.
 				foreach (Directory existing_root in roots) {
 					if (existing_root.FullName == root.FullName) {
-						throw new Exception ("Attempt to re-add root " + root.FullName);
+						return null;
 						// FIXME: Is there a case where we would
 						// want to just return existing_root?
 					}
@@ -513,6 +552,12 @@ namespace Beagle.Daemon.FileSystemQuerya
 			return root;
 		}
 
+		public bool DelRoot (string path)
+		{
+			// FIXME: I need to be written!
+			return true;
+		}
+
 		///////////////////////////////////////////////////////////////////////////
 
 		public Directory GetDirectoryByUniqueId (Guid uid)
diff -urNpX dontdiff beagle-orig/beagled/FileSystemQueryable/FileSystemQueryable.cs beagle/beagled/FileSystemQueryable/FileSystemQueryable.cs
--- beagle-orig/beagled/FileSystemQueryable/FileSystemQueryable.cs	2005-03-26 23:51:12.000000000 +0000
+++ beagle/beagled/FileSystemQueryable/FileSystemQueryable.cs	2005-03-28 19:22:40.000000000 +0100
@@ -267,10 +267,7 @@ namespace Beagle.Daemon.FileSystemQuerya
 		public void StartWorker ()
 		{
 			event_backend.Start (this);
-
-			// FIXME: Shouldn't be hard-wired
-			model.AddRoot (PathFinder.HomeDir);
-
+			Conf.UpdateEvent += model.LoadConf;
 			log.Info ("FileSystemQueryable start-up thread finished");
 			
 			// FIXME: Do we need to re-run queries when we are fully started?
diff -urNpX dontdiff beagle-orig/beagled/RemoteControlImpl.cs beagle/beagled/RemoteControlImpl.cs
--- beagle-orig/beagled/RemoteControlImpl.cs	2005-03-26 23:51:12.000000000 +0000
+++ beagle/beagled/RemoteControlImpl.cs	2005-03-31 08:33:11.000000000 +0100
@@ -51,6 +51,11 @@ namespace Beagle.Daemon {
 		{
 			return QueryDriver.GetIndexInformation ();
 		}
+
+		override public void ReloadConfig ()
+		{
+			Conf.Load ();
+		}
 	}
 
 }
diff -urNpX dontdiff beagle-orig/doc/TODO beagle/doc/TODO
--- beagle-orig/doc/TODO	2005-03-26 23:51:16.000000000 +0000
+++ beagle/doc/TODO	2005-03-31 01:00:03.000000000 +0100
@@ -55,3 +55,16 @@ Mail
   text/plain parts of a mail; at the very least it could index the
   HTML parts of a mail message.
 
+
+Configuration
+=============
+
+* Protection against bad (unparsable) config
+* Force a config reload via dbus (useful for non-inotify users)
+* Make beagle-config send the above dbus command on every change
+* Make beagle-config have a commandline option to ask beagled to update
+* Subscriptions to UpdateHandler, so that you only get called if your subsection
+  has changed since the last load.
+* Code annotation.
+* GUI util to manage configuration. (fredrik?)
+
diff -urNpX dontdiff beagle-orig/tools/beagle-config.1 beagle/tools/beagle-config.1
--- beagle-orig/tools/beagle-config.1	1970-01-01 01:00:00.000000000 +0100
+++ beagle/tools/beagle-config.1	2005-03-31 08:57:26.000000000 +0100
@@ -0,0 +1,55 @@
+.\" beagle-config(1) manpage
+.\"
+.\" Copyright (C) 2005 Novell, Inc.
+.\"
+.TH BEAGLE-CONFIG "1" "Mar 2005" "beagle" "Linux User's Manual"
+.SH NAME
+beagle-config \- command-line interface to the Beagle configuration file
+.SH SYNOPSIS
+.B beagle-config
+\fIoptions\fR
+.br
+.B beagle-config
+\fIsections\fR
+.br
+.B beagle-config
+\fIsections\fR \fIsectionoptions\fR [\fIparams\fR]
+.SH DESCRIPTION
+.BR beagle-config
+is a command line tool designed to manipulate the Beagle config file, typically found at \fI~/.beagle/config.xml\fR
+.PP
+The configuration is stored in \fBXML\fR format. It is split up into \fIsection\fR nodes, all underneath the main document element node \fB<beagle>\fR.
+.PP
+Each \fIsection\fR configures a different area of the Beagle system. Each section has a number of preset \fIsectionoptions\fR (commands) which you can perform on it via this command-line application.
+.PP
+The available sections, and available options for each section, are discovered at runtime. This manual does not attempt to document the sections in detail. This manual demonstrates how you can retrieve a list of available sections and their options.
+.PP
+\fIbeagle-config\fR can be used "offline", it does not require a Beagle daemon to be running for most operations. If a Beagle daemon is running, \fIbeagle-config\fR will ask the Beagle daemon to reload the configuration file after making any changes to it.
+.SH OPTIONS
+.TP
+.B --help 
+Print a brief copyright and usage message.
+.TP
+.B --beagled-reload-config
+Asks the beagle daemon to reload the configuration file.
+.TP
+.B --list-sections
+Lists all of the available sections for use as the \fIsections\fR parameter.
+.SH SECTION OPTIONS
+Each section has its own unique set of options available. To see a list of supported options for a particular section, run \fBbeagle-config sectionname\fR with no additional parameters.
+.SH PARAMS
+Each option may take a number of parameters (or none). Please refer to online documentation if you require explanations of every available command.
+.SH AUTHOR
+Originally written by Daniel Drake <dsd@gentoo.org>.
+.SH "REPORTING BUGS"
+Report bugs to <dashboard-hackers@gnome.org>.
+.SH COPYRIGHT
+Copyright \(co 2005 Novell, Inc.
+.sp
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH "SEE ALSO"
+.BR beagled (1),
+.BR beagle-shutdown (1),
+.BR beagle-status (1),
+.BR best (1)
diff -urNpX dontdiff beagle-orig/tools/Config.cs beagle/tools/Config.cs
--- beagle-orig/tools/Config.cs	1970-01-01 01:00:00.000000000 +0100
+++ beagle/tools/Config.cs	2005-03-31 08:55:44.000000000 +0100
@@ -0,0 +1,189 @@
+//
+// Config.cs
+//
+// Copyright (C) 2005 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 System.Collections;
+using System.Collections.Specialized;
+using System.Reflection;
+
+using Beagle;
+using Beagle.Util;
+
+public static class ConfigTool {
+
+	private static void PrintUsageAndExit ()
+	{
+		string usage =
+			"beagle-config: Command-line interface to the Beagle config file.\n" +
+			"Web page: http://www.gnome.org/projects/beagle\n" +
+			"Copyright (C) 2005 Novell, Inc.\n\n";
+		usage +=
+			"Usage: beagle-config [OPTIONS]\n" +
+			"   or: beagle-config <SECTION>\n" +
+			"   or: beagle-config <SECTION> <SECTIONOPTION> [PARAMS]\n\n" +
+			"Options:\n" +
+			"  --beagled-reload-config\tAsk the beagle daemon to reload\n" +
+			"                         \tthe configuration file.\n" +
+			"  --list-sections\t\tList all available configuration sections.\n" +
+			"  --help\t\t\tPrint this usage message.\n\n" +
+			"If a section is specified with no options, then a list of the available commands for that section is shown.\n";
+
+		Console.WriteLine (usage);
+
+		System.Environment.Exit (0);
+	}
+
+	private static void ListSectionsAndExit ()
+	{
+		Console.WriteLine ("Available configuration sections: ");
+		foreach (string key in Conf.Sections.Keys)
+			Console.WriteLine (" - {0}", key);
+
+		System.Environment.Exit (0);
+	}
+	
+	private static void ListSectionOptionsAndExit (string sectionname, Hashtable options)
+	{
+		Console.WriteLine ("Available options for section '{0}':", sectionname);
+		foreach (string key in options.Keys) {
+			Console.Write (" - {0}", key);
+			if (options [key] != null)
+				Console.Write (" ({0})", options [key]);
+
+			Console.WriteLine ();
+		}
+		
+		System.Environment.Exit (0);
+	}
+		
+	private static void BeagledReloadConfig (bool quiet)
+	{
+		try {
+			RemoteControl.ReloadConfig ();
+		} catch (Exception e) {
+			if (! quiet) {
+				Console.Error.WriteLine ("ERROR: Could not query the beagle daemon.");
+				Console.Error.WriteLine (e.Message);
+			}
+		}
+	}
+
+	public static void Main (string [] args)
+	{
+		if (args.Length == 0)
+			PrintUsageAndExit ();
+
+		int i = 0;
+		while (i < args.Length) {
+			switch (args [i]) {
+			case "--list-sections":
+				ListSectionsAndExit ();
+				return;
+
+			case "--beagled-reload-config":
+				BeagledReloadConfig (false);
+				return;
+
+			case "--help":
+			case "--usage":
+				PrintUsageAndExit ();
+				return;
+
+			default:
+				break;
+			}
+			++i;
+		}
+
+		Conf.Load ();
+
+		string sectionname = args [0];
+
+		if (! Conf.Sections.ContainsKey (sectionname)) {
+			Console.Error.WriteLine ("ERROR: Invalid section name '{0}'", sectionname);
+			Environment.Exit (-1);
+		}
+
+		// Find all of the methods ("options") inside the specified section
+		// object which have the SectionOption attribute.
+		object section = Conf.Sections [sectionname];
+		MemberInfo [] members = section.GetType ().GetMembers ();
+		Hashtable options = new Hashtable ();
+
+		foreach (MemberInfo member in members) {
+			object [] attrs = member.GetCustomAttributes (typeof (Conf.SectionOption), false);
+			if (attrs.Length == 0)
+				continue;
+
+			// Store the name and description in a hashtable
+			options.Add (member.Name, ((Conf.SectionOption)attrs[0]).Description);
+		}
+	
+		// No option specified?
+		if (args.Length == 1)
+			ListSectionOptionsAndExit (sectionname, options);
+		
+		string optionname = args [1];
+		if (! options.ContainsKey (optionname)) {
+			Console.Error.WriteLine ("ERROR: Invalid option name '{0}'", optionname);
+			Environment.Exit (-2);
+		}
+
+		//
+		// Invoke the method the user has chosen
+		//
+		MethodInfo method = section.GetType ().GetMethod (optionname);
+
+		// Can't pass a reference in a MethodInfo.Invoke() call so we box the
+		// output in a single-element array.
+		string [] boxoutput = new string [1];
+
+		// Pack the remaining command line params into an array used for
+		// params of the method.
+		string [] optionparams = new string [args.Length - 2];
+		int j, k;
+		for (j = 0, k = 2; k < args.Length; j++, k++)
+			optionparams [j] = args [k];
+
+		object [] methodparams = { boxoutput, optionparams };
+		bool result = (bool) method.Invoke (section, methodparams);
+
+		// Read the result and show the output
+		if (result == true)
+			Console.WriteLine (boxoutput [0]);
+		else {
+			Console.Error.WriteLine ("ERROR: Command execution failed.");
+			Console.Error.WriteLine (boxoutput [0]);
+			Environment.Exit (-3);
+		}
+
+		BeagledReloadConfig (true);
+		Environment.Exit (0);
+
+	}
+
+
+}
diff -urNpX dontdiff beagle-orig/tools/Makefile.am beagle/tools/Makefile.am
--- beagle-orig/tools/Makefile.am	2005-03-26 23:51:29.000000000 +0000
+++ beagle/tools/Makefile.am	2005-03-31 00:59:38.000000000 +0100
@@ -19,6 +19,16 @@ WRAPPER_SED = sed 					\
 	-e "s|\@libdir\@|$(libdir)|g"			\
 	-e "s|\@gacprefix\@|$(GAC_PREFIX)|g"
 
+CONFIG_TARGET  = Config.exe
+CONFIG_WRAPPER = beagle-config
+CONFIG_CSFILES = $(srcdir)/Config.cs
+
+$(CONFIG_TARGET): $(CONFIG_CSFILES) $(LOCAL_ASSEMBLIES)
+	$(CSC) -o $@ $(CSFLAGS) $(CONFIG_CSFILES) $(ASSEMBLIES)
+
+$(CONFIG_WRAPPER): $(WRAPPER_IN)
+	$(WRAPPER_SED) -e "s|\@target\@|$(CONFIG_TARGET)|g" < $(srcdir)/$(WRAPPER_IN) > $@
+	chmod +x $(CONFIG_WRAPPER)
 
 QUERY_TARGET  = Query.exe
 QUERY_WRAPPER = beagle-query
@@ -54,11 +64,13 @@ $(EXERCISE_FILE_SYSTEM_WRAPPER): $(WRAPP
 	chmod +x $(EXERCISE_FILE_SYSTEM_WRAPPER)
 
 TARGETS = 				\
+	$(CONFIG_TARGET)		\
 	$(QUERY_TARGET)                 \
 	$(INDEX_WEB_CONTENT_TARGET)	\
 	$(EXERCISE_FILE_SYSTEM_TARGET)
 
 WRAPPERS = 				\
+	$(CONFIG_WRAPPER)		\
 	$(QUERY_WRAPPER)		\
 	$(INDEX_WEB_CONTENT_WRAPPER)	\
 	$(EXERCISE_FILE_SYSTEM_WRAPPER)
@@ -71,6 +83,7 @@ bin_SCRIPTS = 			\
 	beagle-status
 
 man_MANS = 			\
+	beagle-config.1		\
 	beagle-query.1		\
 	beagle-shutdown.1	\
 	beagle-status.1
diff -urNpX dontdiff beagle-orig/Util/Conf.cs beagle/Util/Conf.cs
--- beagle-orig/Util/Conf.cs	1970-01-01 01:00:00.000000000 +0100
+++ beagle/Util/Conf.cs	2005-03-31 08:47:55.000000000 +0100
@@ -0,0 +1,374 @@
+//
+// Conf.cs
+//
+// Copyright (C) 2005 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 System.ComponentModel;
+using System.Collections;
+using System.IO;
+using System.Text;
+using System.Xml;
+using Beagle.Util;
+
+namespace Beagle.Util {
+
+	public static class Conf {
+
+		private static string filepath;
+		private static string storedir;
+		private static XmlDocument document;
+		private static ArrayList subscribers;
+		private static DateTime mtime;
+
+		public delegate void UpdateHandler ();
+		public static event UpdateHandler UpdateEvent;
+
+		private static int inotify_wd;
+
+		private static IndexingSection indexing;
+		public static IndexingSection Indexing {
+			get { return indexing; }
+		}
+
+		private static Hashtable sections;
+		public static Hashtable Sections {
+			get { return sections; }
+		}
+
+		static Conf ()
+		{
+			// FIXME use pathfinder. (outside the daemon- how?)
+			storedir = Path.Combine (Environment.GetEnvironmentVariable ("HOME"), ".beagle");
+			filepath = Path.Combine (storedir, "config.xml");
+			document = new XmlDocument ();
+
+			sections = new Hashtable (1);
+			indexing = new IndexingSection ();
+
+			sections.Add ("indexing", indexing);
+		}
+
+		private static void CheckConfig ()
+		{
+			if (! File.Exists (filepath)) {
+				// Copy default config over
+
+				// FIXME: dont hardcode /usr/local/share
+				File.Copy ("/usr/local/share/beagle/default-config.xml", filepath);
+			}
+		}
+
+		public static void Load  ()
+		{
+			CheckConfig();
+
+			// Check that file has been changed since last load
+			if (mtime == File.GetLastWriteTime (filepath))
+				return;
+
+			document.Load (filepath);
+			ProcessContent ();
+
+			// Inform all "subscribed" users of the new config
+			if (UpdateEvent != null)
+				UpdateEvent ();
+
+			mtime = File.GetLastWriteTime (filepath);
+		}
+
+		private static void ProcessContent ()
+		{
+			XmlNode parent = document.DocumentElement;
+
+			if (parent.Name != "beagle")
+				throw new XmlException ("Not a beagle config file.");
+
+			foreach (XmlNode node in parent.ChildNodes) {
+				if (node.NodeType != XmlNodeType.Element)
+					continue;
+
+				IConfSection handler = (IConfSection) sections [node.Name];
+				// FIXME might not exist...
+				handler.ProcessContent (node);
+			}
+		}
+
+		public static void WatchForUpdates ()
+		{
+			// We require inotify for automatic updates.
+			// FIXME: Should we also support non-inotify through a FSW?
+			if (! Inotify.Enabled)
+				return;
+
+			Inotify.Event += OnInotifyEvent;
+			inotify_wd = Inotify.Watch (storedir, Inotify.EventType.Modify | Inotify.EventType.MovedTo);
+		}
+
+		private static void OnInotifyEvent (int wd, string path, string subitem,
+						string srcpath, Inotify.EventType type)
+		{
+			if (wd != inotify_wd)
+				return;
+
+			// File has changed, reload
+			Load ();
+		}
+
+		public static void Save ()
+		{
+			XmlTextWriter writer = new XmlTextWriter (filepath, Encoding.UTF8);
+			writer.Formatting = Formatting.Indented;
+			writer.IndentChar = '\t';
+			writer.Indentation = 1;
+			document.Save (writer);
+			writer.Close ();
+		}
+
+		private static void AddNode (string nodename, string content, string attrname,
+						string attrcontent, XmlNode root, Hashtable list)
+		{
+			XmlElement node = document.CreateElement (nodename);
+			XmlText text = document.CreateTextNode (content);
+			
+			if (attrname != null)
+				node.SetAttribute (attrname, attrcontent);
+			
+			node.AppendChild (text);
+			root.AppendChild (node);
+			list.Add (content, node);
+			Save ();
+		}
+
+		private static void DelNode (string child, XmlNode parent, Hashtable list)
+		{
+			XmlNode childnode = (XmlNode) list [child];
+			parent.RemoveChild (childnode);
+			list.Remove (child);
+			Conf.Save ();
+		}
+
+		public class IndexingSection : IConfSection {
+
+			private XmlNode root;
+
+			private Hashtable roots;
+			private Hashtable specialroots;
+			private Hashtable ignorepatterns;
+
+			public IList Roots {
+				get { return new ArrayList (roots.Keys); }
+			}
+
+			public IList SpecialRoots {
+				get { return new ArrayList (specialroots.Keys); }
+			}
+			
+			public IList IgnorePatterns {
+				get { return new ArrayList (ignorepatterns.Keys); }
+			}
+			
+			public IndexingSection ()
+			{
+				roots = new Hashtable ();
+				specialroots = new Hashtable ();
+				ignorepatterns = new Hashtable ();
+			}
+			
+			public void ProcessContent (XmlNode parent)
+			{
+				this.root = parent;
+
+				foreach (XmlNode node in parent.ChildNodes) {
+					if (node.NodeType != XmlNodeType.Element)
+						continue;
+
+					string content = node.FirstChild.Value;
+
+					if (node.Name == "index")
+						Index (node, content);
+					else if (node.Name == "ignore")
+						ignorepatterns.Add (content, node);
+				}
+
+			}
+
+			private void Index (XmlNode node, string content)
+			{
+				string type = null;
+				XmlNode attr = node.Attributes.GetNamedItem ("type");
+				if (attr != null)
+					type = attr.Value;
+				
+				if (type == "special")
+					specialroots.Add (content, node);
+				else
+					roots.Add (content, node);
+			}
+
+			[SectionOption (Description="List the indexing roots")]
+			public bool ListRoots (string [] output, string [] args)
+			{
+				output [0] = "Current roots:\n";
+				if (specialroots.Contains ("homedir"))
+					output [0] += " - Your home directory\n";
+				foreach (string root in roots.Keys)
+					output [0] += " - " + root + "\n";
+
+				return true;
+			}
+
+			[SectionOption (Description="Add another root directory to be indexed")]
+			public bool AddRoot (string [] output, string [] args)
+			{
+				if (args.Length != 1) {
+					output [0] = "AddRoot requires one parameter: A path";
+					return false;
+				}
+
+				string root = args [0];
+				
+				if (roots.ContainsKey (root)) {
+					output [0] = "Root '" + root + "' is already listed.";
+					return false;
+				}
+				
+				AddNode ("index", root, null, null, this.root, roots);
+				output [0] = "Root added.";
+				return true;
+			}
+
+			[SectionOption (Description="Delete a root")]
+			public bool DelRoot (string [] output, string [] args)
+			{
+				if (args.Length != 1) {
+					output [0] = "DelRoot requires one parameter: A path";
+					return false;
+				}
+
+				string root = args [0];
+
+				if (! roots.ContainsKey (root)) {
+					output [0] = "Root '" + root + "' is not listed.";
+					return false;
+				}
+
+				DelNode (root, this.root, roots);
+				output [0] = "Root removed.";
+				return true;
+			}
+
+			[SectionOption (Description="Add your home directory as a root to be indexed")]
+			public bool AddHomeDirRoot (string [] output, string [] args)
+			{
+				if (specialroots.ContainsKey ("homedir")) {
+					output [0] = "Your home directory is already marked to be indexed.";
+					return false;
+				}
+
+				AddNode ("index", "homedir", "type", "special", this.root, specialroots);
+				output [0] = "Root added.";
+				return true;
+			}
+
+			[SectionOption (Description="Prevent your home directory from being indexed")]
+			public bool DelHomeDirRoot (string [] output, string [] args)
+			{
+				if (! specialroots.ContainsKey ("homedir")) {
+					output [0] = "Your home directory is not marked for indexing.";
+					return false;
+				}
+
+				DelNode ("homedir", this.root, specialroots);
+				output [0] = "Root removed";
+				return true;
+			}
+
+			[SectionOption (Description="List filename patterns to be ignored")]
+			public bool ListIgnorePatterns (string [] output, string [] args)
+			{
+				output [0] = "Current ignore patterns:\n";
+				foreach (string pattern in ignorepatterns.Keys)
+					output [0] += " - " + pattern + "\n";
+
+				return true;
+			}
+
+			[SectionOption (Description="Add a filename pattern to be ignored")]
+			public bool AddIgnorePattern (string [] output, string [] args)
+			{
+				if (args.Length != 1) {
+					output [0] = "AddIgnorePattern requires one parameter: A pattern";
+					return false;
+				}
+
+				string pattern = args [0];
+
+				if (ignorepatterns.ContainsKey (pattern)) {
+					output [0] = "Pattern '" + pattern + "' is already ignored.";
+					return false;
+				}
+
+				AddNode ("ignore", pattern, null, null, this.root, ignorepatterns); 
+				output [0] = "Ignore pattern added.";
+				return true;
+			}
+
+			[SectionOption (Description="Delete a filename pattern from the ignore list")]
+			public bool DelIgnorePattern (string [] output, string [] args)
+			{
+				if (args.Length != 1) {
+					output [0] = "DelIgnorePattern requires one parameter: A pattern";
+					return false;
+				}
+
+				string pattern = args [0];
+
+				if (! ignorepatterns.ContainsKey (pattern)) {
+					output [0] = "Pattern '" + pattern + "' is not ignored.";
+					return false;
+				}
+
+				DelNode (pattern, this.root, ignorepatterns);
+				output [0] = "Ignore pattern removed.";
+				return true;
+			}
+
+		}
+
+		public class SectionOption : Attribute {
+				
+			public string Description;
+			
+		}
+
+	}
+
+	public interface IConfSection {
+			
+		void ProcessContent (XmlNode node);
+
+	}
+}
+
diff -urNpX dontdiff beagle-orig/Util/default-config.xml.in beagle/Util/default-config.xml.in
--- beagle-orig/Util/default-config.xml.in	1970-01-01 01:00:00.000000000 +0100
+++ beagle/Util/default-config.xml.in	2005-03-28 18:32:43.000000000 +0100
@@ -0,0 +1,46 @@
+<beagle ver="@VERSION@">
+
+	<indexing>
+
+		<index type="special">homedir</index>
+
+		<ignore>.*</ignore>
+		<ignore>#*#</ignore>
+		<ignore>*.o</ignore>
+		<ignore>*.a</ignore>
+		<ignore>*.S</ignore>
+		<ignore>*.la</ignore>
+		<ignore>*.lo</ignore>
+		<ignore>*.loT</ignore>
+		<ignore>*.so</ignore>
+		<ignore>*.exe</ignore>
+		<ignore>*.dll</ignore>
+		<ignore>*.mdb</ignore>
+		<ignore>*.com</ignore>
+		<ignore>*.csproj</ignore>
+		<ignore>*.dsp</ignore>
+		<ignore>*.dsw</ignore>
+		<ignore>*.m4</ignore>
+		<ignore>*.pc</ignore>
+		<ignore>*.pc.in</ignore>
+		<ignore>*.omf</ignore>
+		<ignore>*.aux</ignore>
+		<ignore>*.tmp</ignore>
+		<ignore>autom4te.cache</ignore>
+		<ignore>po</ignore>
+		<ignore>aclocal</ignore>
+		<ignore>Makefile</ignore>
+		<ignore>Makefile.am</ignore>
+		<ignore>Makefile.in</ignore>
+		<ignore>CVS</ignore>
+		<ignore>SCCS</ignore>
+		<ignore>conftest</ignore>
+		<ignore>confdefs.h</ignore>
+		<ignore>conftest.*</ignore>
+		<ignore>confstat</ignore>
+		<ignore>/conf[0-9]+.sh/</ignore>
+		<ignore>/conf[0-9]+.file/</ignore>
+
+	</indexing>
+
+</beagle>
diff -urNpX dontdiff beagle-orig/Util/Makefile.am beagle/Util/Makefile.am
--- beagle-orig/Util/Makefile.am	2005-03-26 23:51:11.000000000 +0000
+++ beagle/Util/Makefile.am	2005-03-28 18:34:37.000000000 +0100
@@ -15,9 +15,16 @@ GOOGLE_CS   = GoogleSearch.cs
 $(GOOGLE_CS): $(GOOGLE_WSDL)
 	wsdl -namespace:Beagle.Util -out:$@ $^
 
+DEFAULT_CONFIG = default-config.xml
+DEFAULT_CONFIG_IN = default-config.xml.in
+
+$(DEFAULT_CONFIG): $(srcdir)/$(DEFAULT_CONFIG_IN)
+	sed -e "s|\@VERSION\@|$(VERSION)|g" $(srcdir)/$(DEFAULT_CONFIG_IN) > $@
+
 CSFILES = 			        	\
 	$(srcdir)/camel.cs              	\
 	$(srcdir)/CommandLineFu.cs		\
+	$(srcdir)/Conf.cs			\
 	$(srcdir)/FileAdvise.cs			\
 	$(srcdir)/ExifData.cs			\
 	$(srcdir)/ExceptionHandlingThread.cs	\
@@ -71,11 +78,13 @@ $(TARGET): $(CSFILES) $(GOOGLE_CS)
 Inotify.exe: $(srcdir)/Inotify.cs $(srcdir)/Logger.cs
 	$(CSC) --unsafe -o $@ $^ -r:Mono.Posix
 
-all: $(TARGET) Inotify.exe
+all: $(TARGET) $(DEFAULT_CONFIG) Inotify.exe
 
 install-data-local: $(TARGET)
 	$(mkinstalldirs) $(DESTDIR)$(pkglibdir)
 	$(INSTALL_DATA) $(TARGET) $(DESTDIR)$(pkglibdir)/$(TARGET)
+	$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
+	$(INSTALL_DATA) $(DEFAULT_CONFIG) $(DESTDIR)$(pkgdatadir)/$(DEFAULT_CONFIG)
 
 uninstall-local:
 	rm -f $(DESTDIR)$(pkglibdir)/$(TARGET)
@@ -91,11 +100,13 @@ EXTRA_DIST =			\
 	$(GOOGLE_WSDL)		\
 	$(CSFILES)		\
 	$(COND_CS_FILES)	\
+	$(DEFAULT_CONFIG_IN)	\
 	inotify-test
 
 CLEANFILES =			\
 	$(GOOGLE_CS)		\
 	$(TARGET)		\
 	$(TARGET).mdb		\
+	$(DEFAULT_CONFIG)	\
 	Inotify.exe		\
 	Inotify.exe.mdb
