Fix a bunch of memory problems in beagle:
[beagle.git] / beagled / EvolutionMailDriver / EvolutionMailDriver.cs
blob63f13171fc68b15001c7285dda1f43912e47866e
1 //
2 // EvolutionMailDriver.cs
3 //
4 // Copyright (C) 2004 Novell, Inc.
5 //
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;
34 using Camel = Beagle.Util.Camel;
36 namespace Beagle.Daemon.EvolutionMailDriver {
38 [QueryableFlavor (Name="EvolutionMail", Domain=QueryDomain.Local, RequireInotify=false)]
39 public class EvolutionMailQueryable : LuceneQueryable {
41 public int polling_interval_in_seconds = 60;
43 private string local_path, imap_path, imap4_path;
45 private MailCrawler crawler;
47 private Hashtable generator_progress = new Hashtable ();
49 // Index versions
50 // 1: Original version, stored all recipient addresses as a
51 // RFC822 string
52 // 2: Stores recipients in separate properties,
53 // filters/indexes all attachments
54 // 3: Make email addresses non-keyword, add sanitized version
55 // for searching for parts of an email address.
56 // 4: Make the flags property mutable, and create a property
57 // change Indexable when they change for IMAP generators.
58 private const int INDEX_VERSION = 4;
60 public EvolutionMailQueryable () : base ("EvolutionMailIndex", INDEX_VERSION)
62 this.local_path = Path.Combine (PathFinder.HomeDir, ".evolution/mail/local");
63 this.imap_path = Path.Combine (PathFinder.HomeDir, ".evolution/mail/imap");
64 this.imap4_path = Path.Combine (PathFinder.HomeDir, ".evolution/mail/imap4");
67 private void CrawlHook (Scheduler.Task task)
69 crawler.Crawl ();
70 task.Reschedule = true;
71 task.TriggerTime = DateTime.Now.AddSeconds (polling_interval_in_seconds);
74 //////////////////////////////////////////////////////////////////////////////////////////////
76 private void StartWorker ()
78 Logger.Log.Info ("Starting Evolution mail backend");
80 Stopwatch stopwatch = new Stopwatch ();
81 stopwatch.Start ();
83 // Check that we have data to index
84 if ((! Directory.Exists (this.local_path)) && (! Directory.Exists (this.imap_path))) {
85 // No mails present, repoll every minute
86 Logger.Log.Warn ("Evolution mail store not found, watching for it.");
87 GLib.Timeout.Add (60000, new GLib.TimeoutHandler (CheckForMailData));
88 return;
91 Logger.Log.Debug ("Starting mail crawl");
92 State = QueryableState.Crawling;
93 crawler = new MailCrawler (this.local_path, this.imap_path, this.imap4_path);
94 crawler.MboxAddedEvent += IndexMbox;
95 crawler.SummaryAddedEvent += IndexSummary;
96 crawler.Crawl ();
97 State = QueryableState.Idle;
98 Logger.Log.Debug ("Mail crawl finished");
100 // If we don't have inotify, we have to poll the file system. Ugh.
101 if (! Inotify.Enabled) {
102 Scheduler.Task task = Scheduler.TaskFromHook (new Scheduler.TaskHook (CrawlHook));
103 task.Tag = "Crawling ~/.evolution to find summary changes";
104 task.Source = this;
105 ThisScheduler.Add (task);
108 stopwatch.Stop ();
109 Logger.Log.Info ("Evolution mail driver worker thread done in {0}",
110 stopwatch);
113 public override void Start ()
115 base.Start ();
117 ExceptionHandlingThread.Start (new ThreadStart (StartWorker));
120 private bool CheckForMailData ()
122 if ((! Directory.Exists (this.local_path)) && (! Directory.Exists (this.imap_path)))
123 return true; // continue polling
125 // Otherwise stop polling and start indexing
126 StartWorker();
127 return false;
130 public string Name {
131 get { return "EvolutionMail"; }
134 public void IndexSummary (FileInfo summaryInfo)
136 // If there's already a task running for this folder,
137 // don't interrupt it.
138 if (ThisScheduler.ContainsByTag (summaryInfo.FullName)) {
139 Logger.Log.Debug ("Not adding task for already running task: {0}", summaryInfo.FullName);
140 return;
143 Logger.Log.Debug ("Will index summary {0}", summaryInfo.FullName);
144 EvolutionMailIndexableGeneratorImap generator = new EvolutionMailIndexableGeneratorImap (this, summaryInfo);
145 Scheduler.Task task;
146 task = NewAddTask (generator);
147 task.Tag = summaryInfo.FullName;
148 // IndexableGenerator tasks default to having priority Scheduler.Priority Generator
149 ThisScheduler.Add (task);
151 SetGeneratorProgress (generator, 0);
154 public void IndexMbox (FileInfo mboxInfo)
156 // If there's already a task running for this mbox,
157 // don't interrupt it.
158 if (ThisScheduler.ContainsByTag (mboxInfo.FullName)) {
159 Logger.Log.Debug ("Not adding task for already running task: {0}", mboxInfo.FullName);
160 return;
163 Logger.Log.Debug ("Will index mbox {0}", mboxInfo.FullName);
164 EvolutionMailIndexableGeneratorMbox generator = new EvolutionMailIndexableGeneratorMbox (this, mboxInfo);
165 Scheduler.Task task;
166 task = NewAddTask (generator);
167 task.Tag = mboxInfo.FullName;
168 // IndexableGenerator tasks default to having priority Scheduler.Priority Generator
169 ThisScheduler.Add (task);
171 SetGeneratorProgress (generator, 0);
174 public static Uri EmailUri (string accountName, string folderName, string uid)
176 return new Uri (String.Format ("email://{0}/{1};uid={2}",
177 accountName, folderName, uid));
180 // An embarrassingly unscientific attempt at getting progress
181 // information from the mail backend as a whole. Unfortunately
182 // the IMAP and mbox backends don't have a common unit of
183 // measurement (IMAP has number of messages, mbox number of
184 // bytes), so we can't get anything really accurate. We could
185 // try to normalize the byte count; that'd do us a little
186 // better.
187 public void SetGeneratorProgress (EvolutionMailIndexableGenerator generator, int percent)
189 this.generator_progress [generator] = percent;
191 int i = 0, total_percent = 0;
192 foreach (int progress in this.generator_progress.Values) {
193 total_percent += progress;
194 i++;
197 Logger.Log.Debug ("Overall percent is {0}", (float) total_percent / i);
199 this.ProgressPercent = total_percent / i;
202 public void RemoveGeneratorProgress (EvolutionMailIndexableGenerator generator)
204 this.generator_progress.Remove (generator);
206 int i = 0, total_percent = 0;
207 foreach (int progress in this.generator_progress.Values) {
208 total_percent += progress;
209 i++;
212 Logger.Log.Debug ("Overall percent is {0}", (float) total_percent / i);
214 this.ProgressPercent = total_percent / i;