* Filters/, *Queryable/, beagled/Filter.cs, beagled/LuceneCommon.cs: Allow keyword...
[beagle.git] / beagled / EvolutionDataServerQueryable / BookContainer.cs
blobf7db7574d9fd81a2cdfe2d6cf4894e6b5dd89b76
1 //
2 // BookContainer.cs
3 //
4 // Copyright (C) 2005 Novell, Inc.
5 //
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.
27 using System;
28 using System.Globalization;
29 using System.IO;
31 using Beagle.Util;
33 using Evolution;
35 namespace Beagle.Daemon.EvolutionDataServerQueryable {
37 public class BookContainer : Container {
39 private Book book;
40 private BookView book_view;
41 private bool ignore_first_batch = false;
42 private Scheduler.Priority priority = Scheduler.Priority.Delayed;
44 public BookContainer (Evolution.Source source, EvolutionDataServerQueryable queryable, string fingerprint) : base (source, queryable, fingerprint) { }
46 public override bool OpenClient ()
48 if (!this.source.IsLocal ()) {
49 Logger.Log.Debug ("Skipping remote addressbook {0}", this.source.Uri);
50 return false;
53 try {
54 this.book = new Book (this.source);
55 this.book.Open (true);
56 } catch (Exception e) {
57 Logger.Log.Warn ("Unable to open addressbook {0}: {1}", this.source.Uri, e.Message);
58 return false;
61 return true;
64 public override void OpenView ()
66 this.book_view = this.book.GetBookView (BookQuery.AnyFieldContains (""),
67 new object [0],
68 -1);
70 this.book_view.ContactsAdded += OnContactsAdded;
71 this.book_view.ContactsRemoved += OnContactsRemoved;
72 this.book_view.ContactsChanged += OnContactsChanged;
73 this.book_view.SequenceComplete += OnSequenceComplete;
75 this.book_view.Start ();
78 public override void IndexAll ()
80 // We don't need to do anything here. All of the
81 // contacts will be added as a result of
82 // OnContactsAdded being called for every item
83 // after setting up the BookView.
86 public override void IndexChanges ()
88 // Ignore the torrent of add events that will come in
89 // after the BookView is set up.
90 ignore_first_batch = true;
92 Contact[] added, changed;
93 string[] removed;
95 Logger.Log.Debug ("Getting addressbook changes for {0}", this.source.Uri);
96 this.book.GetChanges ("beagle-" + this.fingerprint, out added, out changed, out removed);
97 Logger.Log.Debug ("Addressbook {0}: {1} added, {2} changed, {3} removed",
98 this.book.Uri, added.Length, changed.Length, removed.Length);
100 foreach (Contact contact in added)
101 AddContact (contact);
103 foreach (Contact contact in changed)
104 AddContact (contact);
106 foreach (string id in removed)
107 RemoveContact (id);
110 public override void Remove ()
112 Logger.Log.Debug ("Removing addressbook source {0}", this.source.Uid);
114 Property prop = Property.NewUnsearched ("fixme:source_uid", this.source.Uid);
115 this.queryable.RemovePropertyIndexable (prop);
117 this.book_view.Stop ();
118 this.book_view.Dispose ();
120 this.book.Dispose ();
123 private void OnContactsAdded (object o, Evolution.ContactsAddedArgs args)
125 if (ignore_first_batch)
126 return;
128 foreach (Evolution.Contact contact in args.Contacts)
129 AddContact (contact);
132 private void OnContactsChanged (object o, Evolution.ContactsChangedArgs args)
134 if (ignore_first_batch)
135 return;
137 foreach (Evolution.Contact contact in args.Contacts)
138 AddContact (contact);
141 private void OnContactsRemoved (object o, Evolution.ContactsRemovedArgs args)
143 if (ignore_first_batch)
144 return;
146 // FIXME: This is a temporary workaround for the
147 // fact that the evolution bindings return a
148 // GLib.List with an object type, but there are
149 // really strings in there.
151 GLib.List id_list = new GLib.List (args.Ids.Handle,
152 typeof (string));
154 foreach (string id in id_list)
155 RemoveContact (id);
158 private void OnSequenceComplete (object o, Evolution.SequenceCompleteArgs args)
160 ignore_first_batch = false;
162 // Now that we're done synching with the original
163 // state of the addressbook, switch all new changes to
164 // Immediate mode
165 priority = Scheduler.Priority.Immediate;
167 Logger.Log.Debug ("Sequence complete!");
170 /////////////////////////////////////
172 // URI scheme is:
173 // contacts:///?source-uid=<value>&contact-uid=<value>
175 // The Uri class sucks SO MUCH ASS. It shits itself
176 // on foo:///?bar so we have to insert something in
177 // before "?bar". This is filed as Ximian bug #76146.
178 // Hopefully it is just a bug in Mono and not a
179 // fundamental problem of the Uri class. Fortunately
180 // Evolution can handle the horribly mangled URIs
181 // that come out of it.
183 private Uri GetContactUri (Evolution.Contact contact) {
184 return GetContactUri (contact.Id);
187 private Uri GetContactUri (string id) {
188 return new Uri (String.Format ("contacts://uri-class-sucks/?source-uid={0}&contact-uid={1}",
189 this.source.Uid, id));
192 /////////////////////////////////////
194 private void AddContact (Evolution.Contact contact)
196 Logger.Log.Debug ("We'll index {0}!", contact.FullName);
197 Indexable indexable = ContactToIndexable (contact);
199 this.queryable.AddIndexable (indexable, this.priority);
202 private void RemoveContact (string id)
204 Logger.Log.Debug ("We'll remove {0}", id);
205 this.queryable.RemoveIndexable (GetContactUri (id));
208 /////////////////////////////////////
210 private string GetPhotoFilename (string id)
212 return Path.Combine (this.queryable.PhotoDir, id);
215 private static DateTime RevStringToDateTime (string date_str)
217 if (date_str == null)
218 return DateTime.MinValue;
220 string[] formats = {
221 "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'",
222 "yyyyMMdd'T'HHmmss'Z'"
225 try {
226 return DateTime.ParseExact (date_str, formats,
227 CultureInfo.InvariantCulture,
228 DateTimeStyles.None);
229 } catch (FormatException) {
230 Logger.Log.Warn ("Unable to parse last revision string: {0}", date_str);
231 return DateTime.MinValue;
235 private Indexable ContactToIndexable (Evolution.Contact contact)
237 DateTime rev = RevStringToDateTime (contact.Rev);
239 Indexable indexable = new Indexable (GetContactUri (contact));
240 indexable.Timestamp = rev;
241 indexable.HitType = "Contact";
243 indexable.AddProperty (Property.NewUnsearched ("fixme:source_uid", this.source.Uid));
244 indexable.AddProperty (Property.NewUnsearched ("fixme:uid", contact.Id));
246 indexable.AddProperty (Property.New ("fixme:FileAs", contact.FileAs));
247 indexable.AddProperty (Property.New ("fixme:FullName", contact.FullName));
248 indexable.AddProperty (Property.New ("fixme:GivenName", contact.GivenName));
249 indexable.AddProperty (Property.New ("fixme:FamilyName", contact.FamilyName));
250 indexable.AddProperty (Property.New ("fixme:Nickname", contact.Nickname));
251 indexable.AddProperty (Property.New ("fixme:AddressLabelHome", contact.AddressLabelHome));
252 indexable.AddProperty (Property.New ("fixme:AddressLabelWork", contact.AddressLabelWork));
253 indexable.AddProperty (Property.New ("fixme:AddressLabelOther", contact.AddressLabelOther));
254 indexable.AddProperty (Property.New ("fixme:AssistantPhone", contact.AssistantPhone));
255 indexable.AddProperty (Property.New ("fixme:BusinessPhone", contact.BusinessPhone));
256 indexable.AddProperty (Property.New ("fixme:BusinessPhone2", contact.BusinessPhone2));
257 indexable.AddProperty (Property.New ("fixme:BusinessFax", contact.BusinessFax));
258 indexable.AddProperty (Property.New ("fixme:CallbackPhone", contact.CallbackPhone));
259 indexable.AddProperty (Property.New ("fixme:CarPhone", contact.CarPhone));
260 indexable.AddProperty (Property.New ("fixme:CompanyPhone", contact.CompanyPhone));
261 indexable.AddProperty (Property.New ("fixme:HomePhone", contact.HomePhone));
262 indexable.AddProperty (Property.New ("fixme:HomePhone2", contact.HomePhone2));
263 indexable.AddProperty (Property.New ("fixme:HomeFax", contact.HomeFax));
264 indexable.AddProperty (Property.New ("fixme:IsdnPhone", contact.IsdnPhone));
265 indexable.AddProperty (Property.New ("fixme:MobilePhone", contact.MobilePhone));
266 indexable.AddProperty (Property.New ("fixme:OtherPhone", contact.OtherPhone));
267 indexable.AddProperty (Property.New ("fixme:OtherFax", contact.OtherFax));
268 indexable.AddProperty (Property.New ("fixme:Pager", contact.Pager));
269 indexable.AddProperty (Property.New ("fixme:PrimaryPhone", contact.PrimaryPhone));
270 indexable.AddProperty (Property.New ("fixme:Radio", contact.Radio));
271 indexable.AddProperty (Property.New ("fixme:Telex", contact.Telex));
272 indexable.AddProperty (Property.NewUnsearched ("fixme:Tty", contact.Tty));
273 indexable.AddProperty (Property.NewKeyword ("fixme:Email1", contact.Email1));
274 indexable.AddProperty (Property.NewKeyword ("fixme:Email2", contact.Email2));
275 indexable.AddProperty (Property.NewKeyword ("fixme:Email3", contact.Email3));
276 indexable.AddProperty (Property.NewUnsearched ("fixme:Mailer", contact.Mailer));
277 indexable.AddProperty (Property.New ("fixme:Org", contact.Org));
278 indexable.AddProperty (Property.New ("fixme:OrgUnit", contact.OrgUnit));
279 indexable.AddProperty (Property.New ("fixme:Office", contact.Office));
280 indexable.AddProperty (Property.New ("fixme:Title", contact.Title));
281 indexable.AddProperty (Property.New ("fixme:Role", contact.Role));
282 indexable.AddProperty (Property.New ("fixme:Manager", contact.Manager));
283 indexable.AddProperty (Property.New ("fixme:Assistant", contact.Assistant));
284 indexable.AddProperty (Property.NewKeyword ("fixme:HomepageUrl", contact.HomepageUrl));
285 indexable.AddProperty (Property.NewKeyword ("fixme:BlogUrl", contact.BlogUrl));
286 indexable.AddProperty (Property.NewUnsearched ("fixme:Categories", contact.Categories));
287 indexable.AddProperty (Property.NewUnsearched ("fixme:Caluri", contact.Caluri));
288 indexable.AddProperty (Property.NewUnsearched ("fixme:Icscalendar", contact.Icscalendar));
289 indexable.AddProperty (Property.New ("fixme:Spouse", contact.Spouse));
290 indexable.AddProperty (Property.New ("fixme:Note", contact.Note));
292 Evolution.ContactPhoto photo = contact.Photo;
294 if (photo.Data != null && photo.Data.Length > 0) {
295 string photo_filename = GetPhotoFilename (contact.Id);
296 Stream s = new FileStream (photo_filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
297 BinaryWriter w = new BinaryWriter (s);
298 w.Write (photo.Data);
299 w.Close ();
300 s.Close ();
302 indexable.AddProperty (Property.NewUnsearched ("beagle:Photo", photo_filename));
305 foreach (string im in contact.ImAim)
306 indexable.AddProperty (Property.NewUnsearched ("fixme:ImAim", im));
307 foreach (string im in contact.ImIcq)
308 indexable.AddProperty (Property.NewUnsearched ("fixme:ImIcq", im));
309 foreach (string im in contact.ImJabber)
310 indexable.AddProperty (Property.NewUnsearched ("fixme:ImJabber", im));
311 foreach (string im in contact.ImMsn)
312 indexable.AddProperty (Property.NewUnsearched ("fixme:ImMsn", im));
313 foreach (string im in contact.ImYahoo)
314 indexable.AddProperty (Property.NewUnsearched ("fixme:ImYahoo", im));
315 foreach (string im in contact.ImGroupwise)
316 indexable.AddProperty (Property.NewUnsearched ("fixme:ImGroupwise", im));
318 String name = "";
319 if (contact.GivenName != null && contact.GivenName != "")
320 name = contact.GivenName;
321 if (contact.FamilyName != null && contact.FamilyName != "")
322 name += " " + contact.FamilyName;
323 if (name.Length > 0)
324 indexable.AddProperty (Property.New ("fixme:Name", name));
326 if (contact.Email1 != null)
327 indexable.AddProperty (Property.NewKeyword ("fixme:Email",
328 contact.Email1));
329 return indexable;