--- beagled/ThunderbirdQueryable/ThunderbirdAccount.cs	2006-04-17 12:55:46.000000000 +0200
+++ beagled/ThunderbirdQueryable/ThunderbirdAccount.cs	2006-04-17 12:15:33.000000000 +0200
@@ -36,25 +36,53 @@
 
 	public class ThunderbirdAccount
 	{
-		private string account_name;
+		private string account_server;
 		private int server_port = -1;
 		private AccountType account_type;
 		private string directory;
 		
-		public ThunderbirdAccount (string name, int server_port, AccountType type, string directory)
+		public ThunderbirdAccount (string server, int server_port, AccountType type, string directory)
 		{
-			this.account_name = name;
+			this.account_server = server;
 			this.server_port = server_port;
 			this.account_type = type;
 			this.directory = directory;
 		}
+		
+		public static int ParsePort (AccountType type)
+		{
+			int port = 0;
+			
+			switch (type) {
+			case AccountType.Pop3:
+				port = 110;
+				break;
+			case AccountType.Imap:
+				port = 143;
+				break;
+			}
+			
+			return port;
+		}
+		
+		public static AccountType ParseAccountType (string type_str)
+		{
+			AccountType type = AccountType.Invalid;
+			
+			if (type_str.ToLower() == "imap")
+				type = AccountType.Imap;
+			else if (type_str.ToLower () == "pop3" || type_str.ToLower () == "none")
+				type = AccountType.Pop3;
+			
+			return type;
+		}
 
-		public string Name {
-			get { return account_name; }
+		public string Server {
+			get { return account_server; }
 		}
 		
 		public int Port {
-			get { return server_port; }
+			get { return (server_port != 0 ? server_port : ParsePort (account_type)); }
 		}
 		
 		public AccountType Type {

--- beagled/ThunderbirdQueryable/ThunderbirdIndexableGenerator.cs	2006-04-17 12:55:46.000000000 +0200
+++ beagled/ThunderbirdQueryable/ThunderbirdIndexableGenerator.cs	2006-04-17 12:16:27.000000000 +0200
@@ -31,6 +31,8 @@
 using Beagle.Util;
 using Beagle.Daemon;
 
+using GMime;
+
 namespace Beagle.Daemon.ThunderbirdQueryable {
 	
 	public class ThunderbirdIndexableGenerator : IIndexableGenerator
@@ -44,9 +46,6 @@
 		private string current_mork_file = null;
 		private IEnumerator mail_enumerator = null; // used with database
 
-		private Inotify.Watch inotify_watch = null;
-		private FileSystemWatcher filesystem_watch = null;
-		
 		public ThunderbirdIndexableGenerator (
 			ThunderbirdIndexer indexer, ThunderbirdAccount account)
 		{
@@ -54,52 +53,29 @@
 			this.account = account;
 			this.mork_files = new Queue ();
 			
-			// Read all mork files inside this accounts directory
-			Queue pending = new Queue ();
-			pending.Enqueue (account.Directory);
-			
-			// Find all .msf files (mork files)
-			while (pending.Count > 0) {
-				string dir = (pending.Dequeue () as string);
-
-				foreach (string subdir in DirectoryWalker.GetDirectories (dir)) {
-					if (Shutdown.ShutdownRequested)
-						return;
-					
-					pending.Enqueue (subdir);
-				}
-				
-				foreach (string file in DirectoryWalker.GetItems (dir, new DirectoryWalker.FileFilter(IsMorkFile)))
-					mork_files.Enqueue (file);
-			}
-			
-			Subscribe ();
-			
-			try {
-				UpdateCurrentMailbox ();
-			} catch (Exception e) {
-				Logger.Log.Warn ("Failed updating mailbox: {0}", e.Message);
-			}
+			indexer.ItemUpdatedEvent += OnItemUpdate;
 		}
-		
-		private bool IsMorkFile (string path, string filename)
-		{
-			if (Path.GetExtension (filename) == ".msf")
-				return true;
-		
-			return false;
-		}
-		
+
 		public bool HasNextIndexable ()
 		{
+			if (current_mork_file == null && mork_files.Count > 0) {
+				try {
+					UpdateCurrentMailbox ();
+				} catch (Exception e) {
+					Logger.Log.Warn ("Failed updating mailbox: {0}", e.Message);
+				}
+			}
+		
 			do {
 				// Move on as long as we have emails to index
 				while (mail_enumerator == null || !mail_enumerator.MoveNext ()) {
 
 					if (mork_files.Count <= 0 || 
-					    (current_mork_file = (string) mork_files.Dequeue ()) ==null ||
+					    (current_mork_file = (string) mork_files.Dequeue ()) == null ||
 					    Shutdown.ShutdownRequested) {
-						Unsubscribe ();
+					    	
+					    	indexer.ItemUpdatedEvent -= OnItemUpdate;
+					    	Logger.Log.Info ("No more mails in {0}", account.Directory);
 						return false;
 					}
 				
@@ -128,7 +104,7 @@
 				// Try to create a GMime.Message
 				if (full_index) {
 					try {
-						message = indexer.FullMessage (mail, indexer.GetMailboxFile (database.Filename));
+						message = FullMessage (mail, GetFullyIndexableFile (database.Filename));
 					} catch (Exception e) { 
 						Logger.Log.Debug ("Full index failed {0}: {1}", mail.Id, e.Message);
 					}
@@ -136,9 +112,9 @@
 			
 				// Fallback code in case we can't do a full index
 				if (message == null)
-					message = indexer.PartialMessage (mail);
+					message = PartialMessage (mail);
 				
-				Indexable indexable = indexer.MorkMailToIndexable (account, mail, message, GetCurrentMailbox());
+				Indexable indexable = MorkMailToIndexable (account, mail, message, CurrentMailbox);
 
 				return indexable;
 			} finally {
@@ -179,104 +155,156 @@
 				return;
 			}
 
-			Logger.Log.Debug ("Switched mailbox to {0} ({1})", GetCurrentMailbox (), account.Name);
+			Logger.Log.Debug ("Switched mailbox to {0} ({1})", CurrentMailbox, account.Server);
 
 			// If full_index is set to true, that means all mails are stored on the harddrive and
 			// mails are to be fully indexed
-			full_index = (indexer.IsFullyIndexable (database.Filename) ? true : false);
+			full_index = (IsFullyIndexable (database.Filename) ? true : false);
 
 			mail_enumerator = database.GetEnumerator ();
 		}
-		
-		public string GetCurrentMailbox ()
+
+		public bool AddMorkFile (string filename)
 		{
-			string mailbox = null;
+			if (!filename.EndsWith (".msf"))
+				return false;
 			
-			if (Path.GetExtension (database.Filename) != ".msf")
-				return mailbox;
+			foreach (string existing in mork_files)
+				if (existing == filename)
+					return false;
 			
-			switch (account.Type) {
-			case AccountType.Pop3:
-			case AccountType.Invalid:
-				mailbox = database.Filename.Substring (account.Directory.Length+1);
-				mailbox = indexer.GetMailboxFile (mailbox);
-				break;
-			case AccountType.Imap:
-				if (Path.GetFileName (database.Filename) == "INBOX.msf")
-					mailbox = ".INBOX";
-				else {
-					mailbox = database.Filename.Substring (account.Directory.Length+1);
-					mailbox = indexer.GetMailboxFile (mailbox);
-					mailbox = "." + mailbox.Replace (".sbd/", ".");	
-				}
-				
-				break;
-			}
+			mork_files.Enqueue (filename);
 			
-			return mailbox;
+			return true;
 		}
 		
-		public void Subscribe ()
+		// Partially stolen from the Evolution backend
+		public Indexable MorkMailToIndexable (ThunderbirdAccount account,
+			ThunderbirdMail mail, GMime.Message message, string mailbox)
+		{
+			Indexable indexable;
+
+			indexable = new Indexable (NewMailUri (account, mailbox, mail.Id));		
+			indexable.HitType = "MailMessage";
+			indexable.MimeType = "message/rfc822";
+			indexable.CacheContent = false;
+
+			indexable.AddProperty (Property.NewKeyword ("fixme:client", "thunderbird"));
+			indexable.AddProperty (Property.NewKeyword ("fixme:account", account.Server));
+			indexable.AddProperty (Property.NewKeyword ("fixme:folder", mailbox));
+
+			GMime.InternetAddressList addrs;
+
+			addrs = message.GetRecipients (GMime.Message.RecipientType.To);
+			foreach (GMime.InternetAddress ia in addrs) {
+				if (ia.AddressType != GMime.InternetAddressType.Group)
+					indexable.AddProperty (Property.NewKeyword ("fixme:sentTo", ia.Addr));
+			}
+			addrs.Dispose ();
+
+			addrs = message.GetRecipients (GMime.Message.RecipientType.Cc);
+			foreach (GMime.InternetAddress ia in addrs) {
+				if (ia.AddressType != GMime.InternetAddressType.Group)
+					indexable.AddProperty (Property.NewKeyword ("fixme:sentTo", ia.Addr));
+			}
+			addrs.Dispose ();
+
+			addrs = GMime.InternetAddressList.ParseString (GMime.Utils.HeaderDecodePhrase (message.Sender));
+			foreach (GMime.InternetAddress ia in addrs) {
+				if (ia.AddressType != GMime.InternetAddressType.Group)
+					indexable.AddProperty (Property.NewKeyword ("fixme:gotFrom", ia.Addr));
+			}
+			addrs.Dispose ();
+			
+			indexable.SetBinaryStream (message.Stream);
+
+			return indexable;
+		}
+
+		public GMime.Message PartialMessage (ThunderbirdMail mail)
 		{
-			if (Inotify.Enabled && inotify_watch == null) {			
-				Inotify.EventType mask = Inotify.EventType.Delete | 
-					Inotify.EventType.MovedTo | Inotify.EventType.MovedFrom |
-					Inotify.EventType.Modify | Inotify.EventType.Create;
+			GMime.Message message = new GMime.Message (true);
 
-				inotify_watch = Inotify.Subscribe (account.Directory, OnInotifyEvent, mask);
-				
-			} else if (filesystem_watch == null) {
-				filesystem_watch = new FileSystemWatcher ();
-				filesystem_watch.Path = account.Directory;
+			message.Subject = mail.Subject;
+			message.Sender = mail.Sender;
+			message.SetDate (DateTime.Parse (mail.Date), 0); // FIXME: Timezone awareness
 
-				filesystem_watch.Changed += new FileSystemEventHandler (OnFileSystemWatcher);
-				filesystem_watch.Created += new FileSystemEventHandler (OnFileSystemWatcher);
-				filesystem_watch.Deleted += new FileSystemEventHandler (OnFileSystemWatcher);
+			return message;
+		}
 
-				filesystem_watch.EnableRaisingEvents = true;
-			}
+		public GMime.Message FullMessage (ThunderbirdMail mail, string mail_file)
+		{
+			int fd = Mono.Unix.Native.Syscall.open (
+				mail_file, Mono.Unix.Native.OpenFlags.O_RDONLY);
+			
+			StreamFs stream = new StreamFs (fd, mail.MsgOffset, mail.MsgOffset + mail.OfflineMsgSize);
+			Parser parser = new Parser (stream);
+			GMime.Message message = parser.ConstructMessage ();
+			
+			stream.Dispose ();
+			parser.Dispose ();
+
+			return message;
 		}
 		
-		public void Unsubscribe ()
+		// FIXME: Use this method to check if a mail needs to be indexed
+		public bool IsUpToDate (string filename)
 		{
-			if (Inotify.Enabled && inotify_watch != null)
-				inotify_watch.Unsubscribe ();
-			else if (filesystem_watch != null) {
-				filesystem_watch.Changed -= new FileSystemEventHandler (OnFileSystemWatcher);
-				filesystem_watch.Created -= new FileSystemEventHandler (OnFileSystemWatcher);
-				filesystem_watch.Deleted -= new FileSystemEventHandler (OnFileSystemWatcher);
-				filesystem_watch.EnableRaisingEvents = false;
-				filesystem_watch = null;
-			}
+			return false;
 		}
 		
-		public bool AddMorkFile (string filename)
+		public static  string GetFullyIndexableFile (string mork_file)
 		{
-			if (!filename.EndsWith (".msf"))
-				return false;
-			
-			foreach (string existing in mork_files)
-				if (existing == filename)
-					return false;
+			string mailbox_file = Path.Combine (
+				Path.GetDirectoryName (mork_file), 
+				Path.GetFileNameWithoutExtension (mork_file));
 			
-			mork_files.Enqueue (filename);
+			return mailbox_file;
+		}
+		
+		public static Uri NewMailUri (ThunderbirdAccount account, string mailbox, string id)
+		{
+			Uri uri = null;
 			
-			return true;
+			switch (account.Type) {
+				case AccountType.Pop3:
+				case AccountType.Invalid:
+					uri = new Uri (String.Format ("mailbox://{0}/{1}?number={2}", 
+						account.Directory, mailbox, Convert.ToInt32 (id, 16))); 
+					break;
+				case AccountType.Imap:
+					uri = new Uri (String.Format ("imap://{0}:{1}/fetch%3EUID%3E{2}%3E{3}",
+						account.Server, account.Port, mailbox, Convert.ToInt32 (id, 16)));
+					break;
+			}
+
+			return uri;
 		}
 		
-		// FIXME: Use this method to check if a mail needs to be indexed
-		public bool IsUpToDate (string filename)
+		public static bool IsFullyIndexable (string mork_file)
 		{
+			FileInfo file;
+			
+			try {
+				file = new FileInfo (GetFullyIndexableFile (mork_file));
+
+				return (file.Length > 0 ? true : false);
+				
+			} catch (Exception e) { }
+
 			return false;
 		}
 		
-		public void CheckEvent (string filename)
+		protected virtual void OnItemUpdate (ThunderbirdAccount account, string filename)
 		{
+			if (account != this.account)
+				return;
+				
 			bool update = false;
 			
 			if (!(update = AddMorkFile (filename))) {
-				if (File.Exists (filename + ".msf"))
-					update = AddMorkFile (filename + ".msf");
+				if (File.Exists (filename))
+					update = AddMorkFile (filename);
 			}
 
 			if (update) {
@@ -285,23 +313,36 @@
 			}
 		}
 		
-		private void OnInotifyEvent (Inotify.Watch watch,
-						string path,
-						string subItem,
-						string srcpath,
-						Inotify.EventType type)
-		{
-			CheckEvent (Path.Combine (path, subItem));
-		}
-		
-		private void OnFileSystemWatcher (object o, FileSystemEventArgs args)
-		{
-			CheckEvent (args.FullPath);
+		public string CurrentMailbox {
+			get {
+				string mailbox = null;
+			
+				if (Path.GetExtension (database.Filename) != ".msf")
+					return mailbox;
+			
+				switch (account.Type) {
+				case AccountType.Pop3:
+				case AccountType.Invalid:
+					mailbox = database.Filename.Substring (account.Directory.Length+1);
+					mailbox = GetFullyIndexableFile (mailbox);
+					break;
+				case AccountType.Imap:
+					if (Path.GetFileName (database.Filename) == "INBOX.msf")
+						mailbox = ".INBOX";
+					else {
+						mailbox = database.Filename.Substring (account.Directory.Length+1);
+						mailbox = "." + GetFullyIndexableFile (mailbox).Replace (".sbd/", ".");
+					}
+				
+					break;
+				}
+			
+				return mailbox;
+			}
 		}
 
 		public string StatusName {
-			get { return account.Name; }
+			get { return account.Server; }
 		}
 	}
 }
-

--- beagled/ThunderbirdQueryable/ThunderbirdIndexer.cs	2006-04-17 12:55:46.000000000 +0200
+++ beagled/ThunderbirdQueryable/ThunderbirdIndexer.cs	2006-04-17 12:01:03.000000000 +0200
@@ -31,174 +31,180 @@
 using Beagle.Util;
 using Beagle.Daemon;
 
-using GMime;
-
 namespace Beagle.Daemon.ThunderbirdQueryable {
 
 	public class ThunderbirdIndexer
 	{
+		public delegate void ItemUpdateEventHandler (ThunderbirdAccount account, string item);
+		
+		private string thunderbird_root;
 		private ArrayList account_list;
 		private ThunderbirdQueryable queryable;
 		
-		public ThunderbirdIndexer (ThunderbirdQueryable queryable, ArrayList account_list)
+		public ItemUpdateEventHandler ItemUpdatedEvent;
+		
+		public ThunderbirdIndexer (ThunderbirdQueryable queryable, string thunderbird_root)
 		{
-			this.account_list = account_list;
 			this.queryable = queryable;
+			this.thunderbird_root = thunderbird_root;
+			
+			Inotify.Subscribe (thunderbird_root, OnInotifyEvent,
+				Inotify.EventType.Delete | Inotify.EventType.MovedTo);
+				
+			try {
+				account_list = ThunderbirdQueryable.ReadAccounts (thunderbird_root);
+			} catch (Exception e) {
+				// In case we don't have any accounts to index right now, just sit nicely and wait
+				account_list = new ArrayList ();
+			}
+			
+			Logger.Log.Debug ("Starting Thunderbird mail crawling ({0} accounts)", account_list.Count);
 		}
 
 		public void Crawl ()
 		{
-			// Should not happen!
-			if (account_list == null)
-				return;
-
 			foreach (ThunderbirdAccount account in account_list) {
 				if (Shutdown.ShutdownRequested)
 					return;
-					
-				IndexAccount(account);
+
+				IndexDirectory(account, account.Directory);
 			}
 		}
 
-		// Use this method to index a file
-		public void IndexAccount (ThunderbirdAccount account)
+		// Use this method to a directory recursively
+		public void IndexDirectory (ThunderbirdAccount account, string directory)
 		{
-			IIndexableGenerator generator = null;;
+			Queue pending = new Queue ();
+			ThunderbirdIndexableGenerator generator = null;
 			
-			// Make sure we don't index this if it's already being indexed
-			if (queryable.ThisScheduler.ContainsByTag (account.Name)) {
-				Logger.Log.Debug ("Not adding a task for already running task: {0}", account.Name);
-				return;
-			}
-
 			generator = new ThunderbirdIndexableGenerator (this, account);
 			
-			if (generator != null)
-				AddIIndexableTask (generator, account.Directory);
-			else
-				Logger.Log.Debug ("Unable to create generator for: {0}", account.Name);
+			pending.Enqueue (directory);
+			while (pending.Count > 0) {
+				string dir = pending.Dequeue() as string;
+
+				foreach (string subdir in DirectoryWalker.GetDirectories (dir)) {
+					if (Shutdown.ShutdownRequested)
+						pending.Enqueue (subdir);
+				}
+				
+				if (Inotify.Enabled)
+						Inotify.Subscribe (dir, OnInotifyEvent, Inotify.EventType.All);
+				
+				foreach (string file in DirectoryWalker.GetItems (dir, new DirectoryWalker.FileFilter (IsMorkFile))) {
+					if (Shutdown.ShutdownRequested)
+						return;
+					
+					generator.AddMorkFile (file);
+				}
+			}
+
+			AddIIndexableTask (generator as IIndexableGenerator, account.Directory);
 		}
 		
-		public bool IsFullyIndexable (string mork_file)
+		// Use this method to index a file
+		public void IndexFile (ThunderbirdAccount account, string path, string file)
 		{
-			FileInfo file;
+			ThunderbirdIndexableGenerator generator = null;
 			
-			try {
-				file = new FileInfo (GetMailboxFile (mork_file));
-
-				return (file.Length > 0 ? true : false);
-				
-			} catch (Exception e) { }
-
-			return false;
+			if (!IsMorkFile (path, file))
+				return;
+			
+			generator = new ThunderbirdIndexableGenerator (this, account);
+			generator.AddMorkFile (Path.Combine (path, file));
+			
+			AddIIndexableTask (generator as IIndexableGenerator, account.Directory);
 		}
 		
-		public  string GetMailboxFile (string mork_file)
+		private bool IsMorkFile (string path, string filename)
 		{
-			string mailbox_file = Path.Combine (
-				Path.GetDirectoryName (mork_file), 
-				Path.GetFileNameWithoutExtension (mork_file));
-			
-			return mailbox_file;
+			if (Path.GetExtension (filename) == ".msf")
+				return true;
+		
+			return false;
 		}
 		
 		// Add this object to indexing queue
 		private void AddIIndexableTask (IIndexableGenerator generator, string tag)
 		{
-			if (generator == null)
+			// Make sure we don't index this if it's already being indexed or is invalid
+			if (queryable.ThisScheduler.ContainsByTag (tag)) {
+				Logger.Log.Debug ("Not adding a task for already running task: {0}", tag);
+				return;
+			} else if (generator == null)
 				return;
 
 			Scheduler.Task task = queryable.NewAddTask (generator);
 			task.Tag = tag;
 			queryable.ThisScheduler.Add (task);
 		}
-
-		public static Uri NewMailUri (ThunderbirdAccount account, string mailbox, string id)
+		
+		public void UpdateAccounts ()
 		{
-			Uri uri = null;
-			
-			switch (account.Type) {
-				case AccountType.Pop3:
-				case AccountType.Invalid:
-					uri = new Uri (String.Format ("mailbox://{0}/{1}?number={2}", 
-						account.Directory, mailbox, Convert.ToInt32 (id, 16))); 
-					break;
-				case AccountType.Imap:
-					uri = new Uri (String.Format ("imap://{0}:{1}/fetch%3EUID%3E{2}%3E{3}",
-						account.Name, account.Port, mailbox, Convert.ToInt32 (id, 16)));
-					break;
-			}
+			Logger.Log.Debug ("Accounts may have been added or removed");
 
-			return uri;
+			// FIXME: list and account_list should be compared here. If a new account has
+			// been created, use IndexAccount to index it. If an account has been removed,
+			// stop index that account (remove inotify handlers and things like that).
 		}
 		
-		// Partially stolen from the Evolution backend
-		public Indexable MorkMailToIndexable (ThunderbirdAccount account,
-			ThunderbirdMail mail, GMime.Message message, string mailbox)
+		private void OnInotifyEvent (Inotify.Watch watch,
+						string path,
+						string subitem,
+						string srcpath,
+						Inotify.EventType type)
 		{
-			Indexable indexable;
-
-			indexable = new Indexable (NewMailUri (account, mailbox, mail.Id));		
-			indexable.HitType = "MailMessage";
-			indexable.MimeType = "message/rfc822";
-			indexable.CacheContent = false;
-
-			indexable.AddProperty (Property.NewKeyword ("fixme:client", "thunderbird"));
-			indexable.AddProperty (Property.NewKeyword ("fixme:account", account.Name));
-			indexable.AddProperty (Property.NewKeyword ("fixme:folder", mailbox));
-
-			GMime.InternetAddressList addrs;
-
-			addrs = message.GetRecipients (GMime.Message.RecipientType.To);
-			foreach (GMime.InternetAddress ia in addrs) {
-				if (ia.AddressType != GMime.InternetAddressType.Group)
-					indexable.AddProperty (Property.NewKeyword ("fixme:sentTo", ia.Addr));
+			if (subitem == null)
+				return;
+				
+			string full_path = Path.Combine (path, subitem);
+			
+			// If prefs.js is deleted... then we have nothing at all to index
+			if ((type & Inotify.EventType.Delete) != 0 && full_path == Path.Combine (thunderbird_root, "prefs.js")) {
+				account_list = new ArrayList ();
+				return;
 			}
-			addrs.Dispose ();
-
-			addrs = message.GetRecipients (GMime.Message.RecipientType.Cc);
-			foreach (GMime.InternetAddress ia in addrs) {
-				if (ia.AddressType != GMime.InternetAddressType.Group)
-					indexable.AddProperty (Property.NewKeyword ("fixme:sentTo", ia.Addr));
+			
+			// Update in case an account was removed or added
+			// Thunderbird saves prefs.js with a different name and then replacing the old one
+			// by "moving" it over the existing prefs.js. That's why MoveTo is used as inotfy type.
+			if ((type & Inotify.EventType.MovedTo) != 0 && full_path == Path.Combine (thunderbird_root, "prefs.js")) {
+				UpdateAccounts ();
+				return;
 			}
-			addrs.Dispose ();
-
-			addrs = GMime.InternetAddressList.ParseString (GMime.Utils.HeaderDecodePhrase (message.Sender));
-			foreach (GMime.InternetAddress ia in addrs) {
-				if (ia.AddressType != GMime.InternetAddressType.Group)
-					indexable.AddProperty (Property.NewKeyword ("fixme:gotFrom", ia.Addr));
+			
+			// Unsubscribe to directories that have been removed
+			if ((type & Inotify.EventType.Delete) != 0 && (type & Inotify.EventType.IsDirectory) != 0) {
+				watch.Unsubscribe ();
+				return;
 			}
-			addrs.Dispose ();
 			
-			indexable.SetBinaryStream (message.Stream);
-
-			return indexable;
-		}
-
-		public GMime.Message PartialMessage (ThunderbirdMail mail)
-		{
-			GMime.Message message = new GMime.Message (true);
-
-			message.Subject = mail.Subject;
-			message.Sender = mail.Sender;
-			message.SetDate (DateTime.Parse (mail.Date), 0); // FIXME: Timezone awareness
-
-			return message;
-		}
+			// Re-index files when needed
+			if ((type & Inotify.EventType.Modify) != 0) {
+				foreach (ThunderbirdAccount acc in account_list) {
+					if (!path.StartsWith (acc.Directory) || !IsMorkFile (path, subitem))
+						continue;
+
+					if (queryable.ThisScheduler.ContainsByTag (acc.Directory) && ItemUpdatedEvent != null)
+						ItemUpdatedEvent (acc, full_path);
+					else
+						IndexFile (acc, path, subitem);
 
-		public GMime.Message FullMessage (ThunderbirdMail mail, string mail_file)
-		{
-			int fd = Mono.Unix.Native.Syscall.open (
-				mail_file, Mono.Unix.Native.OpenFlags.O_RDONLY);
-			
-			StreamFs stream = new StreamFs (fd, mail.MsgOffset, mail.MsgOffset + mail.OfflineMsgSize);
-			Parser parser = new Parser (stream);
-			GMime.Message message = parser.ConstructMessage ();
+					return;
+				}
+			}
 			
-			stream.Dispose ();
-			parser.Dispose ();
-
-			return message;
+			// Index newly created directories
+			if ((type & Inotify.EventType.Create) != 0 && (type & Inotify.EventType.IsDirectory) != 0) {
+				foreach (ThunderbirdAccount acc in account_list) {
+					if (!path.StartsWith (acc.Directory))
+						continue;
+						
+					IndexDirectory (acc, full_path);
+				
+					return;
+				}
+			}
 		}
 	}
 }

--- beagled/ThunderbirdQueryable/ThunderbirdQueryable.cs	2006-04-17 12:55:46.000000000 +0200
+++ beagled/ThunderbirdQueryable/ThunderbirdQueryable.cs	2006-04-17 00:27:07.000000000 +0200
@@ -39,14 +39,12 @@
 	
 		private string root_dir;
 		private string profile_dir = null;
-		private ArrayList account_list;
 		private ThunderbirdIndexer thunderbird_indexer;
 	
 		public ThunderbirdQueryable () :
 			base ("ThunderbirdIndex")
 		{
 			thunderbird_indexer = null;
-			account_list = new ArrayList ();
 			root_dir = Path.Combine (PathFinder.HomeDir, ".thunderbird");
 			
 			GMime.Global.Init ();
@@ -70,10 +68,7 @@
 				
 				// Get profile path from profiles.ini
 				profile_dir = GetProfilePath (root_dir);
-				
-				// Try to read all mail accounts available
-				ReadThunderbirdProfiles ();
-				
+
 			} catch (Exception e) {
 				// An error or no data to index
 				WaitForData (e.ToString ());
@@ -81,10 +76,9 @@
 			}
 			
 			// Begin to crawl available mailboxes
-			Logger.Log.Debug ("Starting Thunderbird mail crawling ({0} accounts)", account_list.Count);
 			State = QueryableState.Crawling;
 
-			thunderbird_indexer = new ThunderbirdIndexer (this, account_list);
+			thunderbird_indexer = new ThunderbirdIndexer (this, Path.Combine (root_dir, profile_dir));
 			thunderbird_indexer.Crawl ();
 			
 			// We're done with initial scan
@@ -103,12 +97,61 @@
 			return false;
 		}
 		
-		internal void WaitForData (string msg)
+		private void WaitForData (string msg)
 		{
 			GLib.Timeout.Add (60000, new GLib.TimeoutHandler (IndexDataCheck));
 			Logger.Log.Debug (msg);
 		}
+		
+		/*
+		 * The following methods are pure helper methods to make life easier.
+		 */
+
+		public static ArrayList ReadAccounts (string profile_dir)
+		{
+			string line = null;
+			Queue accounts = new Queue();
+			Hashtable tbl = new Hashtable ();
+			ArrayList account_list = new ArrayList ();
+			StreamReader reader = new StreamReader (profile_dir + "/prefs.js");
+			Regex id_reg = new Regex (@"account.account(?<id>\d).server");
+			Regex reg = new Regex (@"user_pref\(""mail\.(?<key>.*)""\s*,\s*(""(?<value>.*)"" | (?<value>.*))\);",
+				RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
+
+			while ((line = reader.ReadLine()) != null) {
+				if (!line.StartsWith ("user_pref(\"mail."))
+					continue;
 
+				try {
+					string key = reg.Match (line).Result ("${key}");
+
+					if (key.StartsWith ("account.account"))
+						accounts.Enqueue (id_reg.Match (key).Result ("${id}"));
+
+					tbl [key] = reg.Match (line).Result ("${value}");
+				} catch (Exception e) { }
+			}
+
+			while (accounts.Count > 0) {
+				string id = "server.server" + (accounts.Dequeue() as string);
+				AccountType type = ThunderbirdAccount.ParseAccountType ((string) tbl [id + ".type"]);
+
+				if (type == AccountType.Invalid)
+					continue;
+
+				try {
+					account_list.Add (new ThunderbirdAccount (
+						String.Format ("{0}@{1}", (string) tbl [id + ".userName"], (string) tbl [id + ".hostname"]), 
+						Convert.ToInt32 ((string) tbl [id + ".port"]),
+						type, (string) tbl [id + ".directory"]));
+				} catch (Exception e) {
+					continue;
+				}
+			}
+			
+			return account_list;
+		}
+		
 		public static string GetProfilePath (string root)
 		{
 			string line, profile = null;
@@ -130,62 +173,6 @@
 
 			return profile;
 		}
-
-		// FIXME: This is a _really_ ugly method, should perhaps be rewritten?
-		public void ReadThunderbirdProfiles ()
-		{
-			string line;
-			Hashtable table = new Hashtable ();
-			StreamReader reader = new StreamReader (root_dir + "/" + profile_dir + "/prefs.js");
-			Regex reg = new Regex (@"user_pref\(" + "\"" + @"mail\.(?<key>.*)" + 
-				"\"" + @"\s*,\s*" + "(\"" + @"(?<value>.*)" + "\"|" + @"(?<value>.*)" + @")\);",
-				RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
-			
-			// Read all mail-accounts and it's data
-			while ((line = reader.ReadLine ()) != null) {
-				try {
-					string key = reg.Match (line).Result ("${key}");
-					string value = reg.Match (line).Result ("${value}");
-					
-					if (key.StartsWith ("account.") || key.StartsWith ("server"))
-						table [key] = value;
-
-				} catch (Exception e) { }
-			}
-			reader.Close ();
-			
-			// Parse the data we actually need
-			foreach (string raw in table.Keys) {
-				Regex tmp;
-				
-				if (!raw.StartsWith ("account.account")|| !raw.EndsWith ("server"))
-					continue;
-				
-				tmp = new Regex (@"account.account(?<nr>\d)");
-				
-				try {
-					AccountType type;
-					int index = Convert.ToInt32 (tmp.Match (raw).Result ("${nr}"));
-					string type_str = (string) table ["server.server" + index + ".type"];
-					
-					if (type_str == "pop3")
-						type = AccountType.Pop3;
-					else if (type_str == "imap")
-						type = AccountType.Imap;
-					else
-						type = AccountType.Invalid;
-					
-					account_list.Add (new ThunderbirdAccount (
-						(string) table ["server.server" + index + ".name"],
-						Convert.ToInt32 ((string) table["server.server" + index + ".port"]), type,
-						(string) table ["server.server" + index + ".directory"]));
-
-				} catch (Exception e) {
-					// Just continue with the next one if we fail
-					continue;
-				}
-			}
-		}
 	}
 }
 
--- search/Tiles/MailAttachment.cs	2006-04-17 12:55:46.000000000 +0200
+++ search/Tiles/MailAttachment.cs	2006-04-17 12:56:54.000000000 +0200
@@ -64,32 +64,18 @@
 			else
 				return hit ["parent:" + name];
 		}
-		
-		public static string GetCommand(string client)
-		{
-			string command = null;
-			
-			if (client == "evolution")
-				command = "evolution";
-			else if (client == "thunderbird")
-				command = "thunderbird-bin";
-			
-			return command;
-		}
 
 		public override void Open ()
 		{
 			string uri_str;
-			string command = GetCommand (GetHitProperty (Hit, "fixme:client"));
+			Process p = MailMessage.GetClientProcess (GetHitProperty (Hit, "fixme:client"));
 
-			if (command == null) {
+			if (p == null) {
 				OpenFromMime (Hit);
 				return;
 			}
 
-			Process p = new Process ();
 			p.StartInfo.UseShellExecute = false;
-			p.StartInfo.FileName = command;
 
 			if (Hit.ParentUriAsString != null)
 				uri_str = Hit.ParentUriAsString;

--- search/Tiles/MailMessage.cs	2006-04-17 12:55:46.000000000 +0200
+++ search/Tiles/MailMessage.cs	2006-04-17 12:56:54.000000000 +0200
@@ -95,38 +95,40 @@
 			return details;
 		}
 		
-		public static string GetCommand(string client)
+		public static Process GetClientProcess (string client)
 		{
-			string command = null;
+			Process p = null;
 			
-			if (client == "evolution")
-				command = "evolution";
-			else if (client == "thunderbird")
-				command = "thunderbird-bin";
+			if (client == "evolution") {
+				p = new Process ();
+				p.StartInfo.FileName = "evolution";
+			} else if (client == "thunderbird") {
+				p = new Process ();
+				p.StartInfo.FileName = "thunderbird";
+				p.StartInfo.Arguments = "-mail ";
+			}
 			
-			return command;
+			return p;
 		}
 
 		public override void Open ()
 		{
 			string uri_str;
-			string command = GetCommand (Hit.GetFirstProperty ("fixme:client"));
+			Process p = GetClientProcess (Hit.GetFirstProperty ("fixme:client"));
 
-			if (command == null) {
+			if (p == null) {
 				OpenFromMime (Hit);
 				return;
 			}
 
-			Process p = new Process ();
 			p.StartInfo.UseShellExecute = false;
-			p.StartInfo.FileName = command;
 
 			if (Hit.ParentUriAsString != null)
 				uri_str = Hit.ParentUriAsString;
 			else
 				uri_str = Hit.UriAsString;
 
-			p.StartInfo.Arguments  = "'" + uri_str + "'";
+			p.StartInfo.Arguments  += "'" + uri_str + "'";
 
 			try {
 				p.Start ();
