Oops, fix a broken part of the patch
[beagle.git] / beagled / KMailQueryable / KMailQueryable.cs
blobf8f4d75d3459fdfaca1e745c6831061ae12176b3
1 //
2 // KMailQueryable.cs
3 //
4 // Copyright (C) 2005 Novell, Inc.
5 // Copyright (C) 2005 Debajyoti Bera
6 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
28 using System;
29 using System.Collections;
30 using System.IO;
31 using System.Threading;
33 using Beagle.Util;
35 namespace Beagle.Daemon.KMailQueryable {
37 [QueryableFlavor (Name="KMail", Domain=QueryDomain.Local, RequireInotify=false)]
38 public class KMailQueryable : LuceneFileQueryable {
40 // for non-inotify case, poll after this number of seconds
41 public const int polling_interval_in_seconds = 300;
42 // mail folder paths
43 private string local_path, dimap_path;
44 // indexers - one for each mailfolder path
45 private KMailIndexer local_indexer, dimap_indexer;
46 // global variable
47 public static bool gmime_initialized = false;
48 public static void InitializeGMime ()
50 if (!gmime_initialized) {
51 GMime.Global.Init ();
52 gmime_initialized = true;
56 // name of the sentmail folder - should be parsed from kmailrc
57 private string sentmail_foldername;
58 public string SentMailFolderName {
59 get { return sentmail_foldername; }
62 public KMailQueryable () : base ("KMailIndex")
64 // the local mail path is different for different distributions
65 local_path = GuessLocalFolderPath ();
66 if (local_path == null) {
67 Logger.Log.Info ("KMail folders not found. Will keep trying ");
68 } else
69 Logger.Log.Info ("Guessing for location of KMail folders ... found at " + local_path);
70 // I hope there is no ambiguity over imap path :P
71 dimap_path = Path.Combine (PathFinder.HomeDir, ".kde");
72 dimap_path = Path.Combine (dimap_path, "share");
73 dimap_path = Path.Combine (dimap_path, "apps");
74 dimap_path = Path.Combine (dimap_path, "kmail");
75 dimap_path = Path.Combine (dimap_path, "dimap");
77 local_indexer = null;
78 dimap_indexer = null;
79 sentmail_foldername = "sent-mail";
82 //////////////////////////////////////////////////////////////////////////////////////////////
84 /**
85 * initial method called by the daemon
87 public override void Start ()
89 base.Start ();
90 ExceptionHandlingThread.Start (new ThreadStart (StartWorker));
93 /**
94 * for non-inotify case, this method is invoked repeatedly
96 private void CrawlHook (Scheduler.Task task)
98 if (local_indexer != null)
99 local_indexer.Crawl ();
100 if (dimap_indexer != null)
101 dimap_indexer.Crawl ();
102 task.Reschedule = true;
103 task.TriggerTime = DateTime.Now.AddSeconds (polling_interval_in_seconds);
107 * called by Start(), starts actual work
108 * create indexers
109 * ask indexers to crawl the mails
110 * for non-inotify case, ask to poll
112 private void StartWorker ()
114 Logger.Log.Info ("Starting KMail backend");
116 Stopwatch stopwatch = new Stopwatch ();
117 stopwatch.Start ();
119 // check if there is at all anything to crawl
120 if ( local_path == null && (!Directory.Exists (dimap_path))) {
121 GLib.Timeout.Add (60000, new GLib.TimeoutHandler (CheckForExistence));
122 Logger.Log.Debug ("KMail directories (local mail) " + dimap_path + " not found, will repoll.");
123 return;
126 Logger.Log.Debug ("Starting mail crawl");
127 State = QueryableState.Crawling;
128 if (local_path != null) {
129 local_indexer = new KMailIndexer (this, "local", local_path);
130 local_indexer.Crawl ();
132 // FIXME: parse kmailrc to get dimap account name
133 if (Directory.Exists (dimap_path)) {
134 dimap_indexer = new KMailIndexer (this, "dimap", dimap_path);
135 dimap_indexer.Crawl ();
137 State = QueryableState.Idle;
138 Logger.Log.Debug ("Mail crawl done");
140 if (! Inotify.Enabled) {
141 Scheduler.Task task = Scheduler.TaskFromHook (new Scheduler.TaskHook (CrawlHook));
142 task.Tag = "Crawling Maildir directories";
143 task.Source = this;
144 task.TriggerTime = DateTime.Now.AddSeconds (polling_interval_in_seconds);
145 ThisScheduler.Add (task);
148 stopwatch.Stop ();
149 Logger.Log.Info ("KMail driver worker thread done in {0}", stopwatch);
152 /**
153 * use this method to determine if we have anything to crawl and index
155 private bool CheckForExistence ()
157 local_path = GuessLocalFolderPath ();
158 if (local_path == null && (!Directory.Exists (dimap_path)))
159 return true;
161 StartWorker();
162 return false;
165 /////////////////////////////////////////////////////////////////////////////
167 // FIXME: How to determine if an mbox hit is valid without scanning the whole file
169 public string Name {
170 get { return "KMail"; }
173 /**
174 * path of local maildir - mine is in ~/.Mail
175 * This is distribution specific. Mandrake puts kmail mails in
176 * ~/.Mail whereas default kmail folder location is ~/Mail
177 * I guess each distribution can fix this path as they know what is
178 * the path.
179 * It is possible to have the path specified in kmailrc. It might not
180 * be present, in which case try to play a guessing game.
181 * Till then, using a guesser to find out which of ~/.Mail and ~/Mail
182 * is valid.
183 * Guesses the kmail local folder path
184 * first try ~/.Mail, then try ~/Mail
185 * then try ~/.kde/share/apps/kmail/mail
187 private string GuessLocalFolderPath ()
189 string locationrc = GetLocalFolderPathFromKmailrc ();
190 //Logger.Log.Debug ("Reading kmail local-mail location from kmailrc: " +
191 // (locationrc == null ? "Unavailable" : locationrc));
192 string location1 = Path.Combine (PathFinder.HomeDir, "Mail");
193 string location2 = Path.Combine (PathFinder.HomeDir, ".Mail");
195 string location3 = Path.Combine (PathFinder.HomeDir, ".kde");
196 location3 = Path.Combine (location3, "share");
197 location3 = Path.Combine (location3, "apps");
198 location3 = Path.Combine (location3, "kmail");
199 location3 = Path.Combine (location3, "mail");
201 if (locationrc != null && GuessLocalFolder (locationrc))
202 return locationrc;
203 else if (GuessLocalFolder (location1))
204 return location1;
205 else if (GuessLocalFolder (location2))
206 return location2;
207 else if (GuessLocalFolder (location3))
208 return location3;
209 else
210 return null;
214 * to check if the path represents a kmail directory:
215 * for all directories and files named "ddd" and not starting with a '.',
216 * there should be matching index file named .ddd.index
218 private bool GuessLocalFolder (string path)
220 if (! Directory.Exists (path))
221 return false;
222 bool flag = true;
224 foreach (string subdirname in DirectoryWalker.GetDirectoryNames (path)) {
225 if (subdirname.StartsWith ("."))
226 continue;
227 // index-file name is of pattern .name.index
228 string indexfile = Path.Combine (path, "." + subdirname + ".index");
229 if (! File.Exists (indexfile)) {
230 flag = false;
231 Logger.Log.Warn ( "KMail backend: " +
232 path +
233 " contains a maildir directory but no corresponding index file. Probably not a KMail mail directory. Ignoring this location!");
234 break;
238 if (! flag)
239 return false;
241 foreach (FileInfo file in DirectoryWalker.GetFileInfos (path)) {
242 if (file.Name.StartsWith ("."))
243 continue;
244 // index-file name is of pattern .name.index
245 string indexfile = Path.Combine (path, "." + file.Name + ".index");
246 if (! File.Exists (indexfile)) {
247 flag = false;
248 Logger.Log.Warn ( "KMail backend: " +
249 path +
250 " contains an mbox file but no corresponding index file. Probably not a KMail mail directory. Ignoring this location!");
251 break;
255 return flag;
259 * tries to extract folder name from ~/.kde/share/config/kmailrc
261 private string GetLocalFolderPathFromKmailrc ()
263 string kmailrc = Path.Combine (PathFinder.HomeDir, ".kde");
264 kmailrc = Path.Combine (kmailrc, "share");
265 kmailrc = Path.Combine (kmailrc, "config");
266 kmailrc = Path.Combine (kmailrc, "kmailrc");
268 if (File.Exists (kmailrc)) {
269 StreamReader reader = new StreamReader (kmailrc);
270 string section = "";
271 string line;
272 while ((line = reader.ReadLine ()) != null) {
273 if (line.StartsWith ("[") && line.EndsWith ("]")) {
274 section = line;
276 if (section == "[General]") {
277 if (line.StartsWith ("folders=") && line.Length > 8) {
278 return StringFu.ExpandEnvVariables (line.Substring(8));
284 return null;