2 // EvolutionMailDriver.cs
4 // Copyright (C) 2004 Novell, Inc.
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.
29 using System
.Collections
;
31 using System
.Threading
;
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 ArrayList running_generators
= new ArrayList ();
50 // 1: Original version, stored all recipient addresses as a
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 // 5: No need for a separate sanitized version of email addresses.
59 private const int INDEX_VERSION
= 5;
61 public EvolutionMailQueryable () : base ("EvolutionMailIndex", INDEX_VERSION
)
63 this.local_path
= Path
.Combine (PathFinder
.HomeDir
, ".evolution/mail/local");
64 this.imap_path
= Path
.Combine (PathFinder
.HomeDir
, ".evolution/mail/imap");
65 this.imap4_path
= Path
.Combine (PathFinder
.HomeDir
, ".evolution/mail/imap4");
68 private void CrawlHook (Scheduler
.Task task
)
71 task
.Reschedule
= true;
72 task
.TriggerTime
= DateTime
.Now
.AddSeconds (polling_interval_in_seconds
);
75 //////////////////////////////////////////////////////////////////////////////////////////////
77 private void StartWorker ()
79 Logger
.Log
.Info ("Starting Evolution mail backend");
81 Stopwatch stopwatch
= new Stopwatch ();
84 // Check that we have data to index
85 if ((! Directory
.Exists (this.local_path
)) && (! Directory
.Exists (this.imap_path
))) {
86 // No mails present, repoll every minute
87 Logger
.Log
.Warn ("Evolution mail store not found, watching for it.");
88 GLib
.Timeout
.Add (60000, new GLib
.TimeoutHandler (CheckForMailData
));
92 Logger
.Log
.Debug ("Starting mail crawl");
93 crawler
= new MailCrawler (this.local_path
, this.imap_path
, this.imap4_path
);
94 crawler
.MboxAddedEvent
+= IndexMbox
;
95 crawler
.SummaryAddedEvent
+= IndexSummary
;
97 Logger
.Log
.Debug ("Mail crawl finished");
99 // If we don't have inotify, we have to poll the file system. Ugh.
100 if (! Inotify
.Enabled
) {
101 Scheduler
.Task task
= Scheduler
.TaskFromHook (new Scheduler
.TaskHook (CrawlHook
));
102 task
.Tag
= "Crawling ~/.evolution to find summary changes";
104 ThisScheduler
.Add (task
);
108 Logger
.Log
.Info ("Evolution mail driver worker thread done in {0}",
112 public override void Start ()
116 ExceptionHandlingThread
.Start (new ThreadStart (StartWorker
));
119 private bool CheckForMailData ()
121 if ((! Directory
.Exists (this.local_path
)) && (! Directory
.Exists (this.imap_path
)))
122 return true; // continue polling
124 // Otherwise stop polling and start indexing
130 get { return "EvolutionMail"; }
133 public void IndexSummary (FileInfo summaryInfo
)
135 // If there's already a task running for this folder,
136 // don't interrupt it.
137 if (ThisScheduler
.ContainsByTag (summaryInfo
.FullName
)) {
138 Logger
.Log
.Debug ("Not adding task for already running task: {0}", summaryInfo
.FullName
);
142 Logger
.Log
.Debug ("Will index summary {0}", summaryInfo
.FullName
);
143 EvolutionMailIndexableGeneratorImap generator
= new EvolutionMailIndexableGeneratorImap (this, summaryInfo
);
145 task
= NewAddTask (generator
);
146 task
.Tag
= summaryInfo
.FullName
;
147 ThisScheduler
.Add (task
);
149 AddGenerator (generator
);
152 public void IndexMbox (FileInfo mboxInfo
)
154 // If there's already a task running for this mbox,
155 // don't interrupt it.
156 if (ThisScheduler
.ContainsByTag (mboxInfo
.FullName
)) {
157 Logger
.Log
.Debug ("Not adding task for already running task: {0}", mboxInfo
.FullName
);
161 Logger
.Log
.Debug ("Will index mbox {0}", mboxInfo
.FullName
);
162 EvolutionMailIndexableGeneratorMbox generator
= new EvolutionMailIndexableGeneratorMbox (this, mboxInfo
);
164 task
= NewAddTask (generator
);
165 task
.Tag
= mboxInfo
.FullName
;
166 ThisScheduler
.Add (task
);
168 AddGenerator (generator
);
171 internal void AddGenerator (EvolutionMailIndexableGenerator generator
)
173 running_generators
.Add (generator
);
176 internal void RemoveGenerator (EvolutionMailIndexableGenerator generator
)
178 running_generators
.Remove (generator
);
181 protected override bool IsIndexing
{
182 get { return running_generators.Count > 0; }
185 protected override int ProgressPercent
{
187 if (running_generators
.Count
== 0)
190 // An embarrassingly unscientific attempt at getting progress
191 // information from the mail backend as a whole. Unfortunately
192 // the IMAP and mbox backends don't have a common unit of
193 // measurement (IMAP has number of messages, mbox number of
194 // bytes), so we can't get anything really accurate.
195 double total_percent
= 0;
197 foreach (EvolutionMailIndexableGenerator generator
in running_generators
)
198 total_percent
+= generator
.ProgressPercent
;
200 return (int) (total_percent
/ running_generators
.Count
);
204 public static Uri
EmailUri (string accountName
, string folderName
, string uid
)
206 return new Uri (String
.Format ("email://{0}/{1};uid={2}",
207 accountName
, folderName
, uid
));