4 // Copyright (C) 2004 Christopher Orr
5 // Copyright (C) 2004 Novell, Inc.
9 // Permission is hereby granted, free of charge, to any person obtaining a
10 // copy of this software and associated documentation files (the "Software"),
11 // to deal in the Software without restriction, including without limitation
12 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 // and/or sell copies of the Software, and to permit persons to whom the
14 // Software is furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
29 using System
.Collections
;
31 using System
.Threading
;
36 namespace Beagle
.Daemon
.TomboyQueryable
{
38 [QueryableFlavor (Name
="Tomboy", Domain
=QueryDomain
.Local
, RequireInotify
=false)]
39 public class TomboyQueryable
: LuceneFileQueryable
{
42 Hashtable note_text_cache
= UriFu
.NewHashtable ();
44 public TomboyQueryable () : base ("TomboyIndex")
46 tomboy_dir
= Path
.Combine (PathFinder
.HomeDir
, ".tomboy");
49 public override void Start ()
53 ExceptionHandlingThread
.Start (new ThreadStart (StartWorker
));
56 private void StartWorker ()
58 if (!Directory
.Exists (tomboy_dir
) ) {
59 GLib
.Timeout
.Add (60000, new GLib
.TimeoutHandler (CheckForExistence
));
63 if (Inotify
.Enabled
) {
64 Inotify
.EventType mask
= Inotify
.EventType
.Delete
|
65 Inotify
.EventType
.MovedTo
|
66 Inotify
.EventType
.MovedFrom
;
68 Inotify
.Subscribe (tomboy_dir
, OnInotifyEvent
, mask
);
70 FileSystemWatcher fsw
= new FileSystemWatcher ();
71 fsw
.Path
= tomboy_dir
;
72 fsw
.Filter
= "*.note";
74 fsw
.Changed
+= new FileSystemEventHandler (OnChanged
);
75 fsw
.Created
+= new FileSystemEventHandler (OnChanged
);
76 fsw
.Deleted
+= new FileSystemEventHandler (OnDeleted
);
78 fsw
.EnableRaisingEvents
= true;
81 // Crawl all of our existing notes to make sure that
82 // everything is up-to-date.
83 Logger
.Log
.Info ("Scanning Tomboy notes...");
85 Stopwatch stopwatch
= new Stopwatch ();
88 DirectoryInfo dir
= new DirectoryInfo (tomboy_dir
);
90 State
= QueryableState
.Crawling
;
91 foreach (FileInfo file
in dir
.GetFiles ()) {
92 if (file
.Extension
== ".note") {
93 IndexNote (file
, Scheduler
.Priority
.Delayed
);
97 State
= QueryableState
.Idle
;
100 Logger
.Log
.Info ("Scanned {0} notes in {1}", count
, stopwatch
);
103 private bool CheckForExistence ()
105 if (!Directory
.Exists (tomboy_dir
))
113 /////////////////////////////////////////////////
115 // Modified/Created/Deleted event using Inotify
116 private void OnInotifyEvent (Inotify
.Watch watch
,
120 Inotify
.EventType type
)
125 if (Path
.GetExtension (subitem
) != ".note")
128 if ((type
& Inotify
.EventType
.MovedTo
) != 0) {
129 IndexNote (new FileInfo (Path
.Combine (path
, subitem
)), Scheduler
.Priority
.Immediate
);
132 if ((type
& Inotify
.EventType
.MovedFrom
) != 0 ||
133 ((type
& Inotify
.EventType
.Delete
) != 0 &&
134 (type
& Inotify
.EventType
.IsDirectory
) == 0))
135 RemoveNote (subitem
);
138 // Modified/Created event using FSW
139 private void OnChanged (object o
, FileSystemEventArgs args
)
141 IndexNote (new FileInfo (args
.FullPath
), Scheduler
.Priority
.Immediate
);
144 // Deleted event using FSW
145 private void OnDeleted (object o
, FileSystemEventArgs args
)
147 RemoveNote (args
.FullPath
);
150 /////////////////////////////////////////////////
152 private Indexable
NoteToIndexable (FileInfo file
, Note note
)
154 Indexable indexable
= new Indexable (note
.Uri
);
156 indexable
.ContentUri
= UriFu
.PathToFileUri (file
.FullName
);
158 indexable
.Timestamp
= note
.timestamp
;
159 indexable
.HitType
= "Note";
160 indexable
.Filtering
= IndexableFiltering
.AlreadyFiltered
;
162 indexable
.AddProperty (Property
.New ("dc:title", note
.subject
));
164 // We remember the note's text so that we can stuff it in
165 // the TextCache later.
166 note_text_cache
[note
.Uri
] = note
.text
;
168 StringReader reader
= new StringReader (note
.text
);
169 indexable
.SetTextReader (reader
);
174 private void IndexNote (FileInfo file
, Scheduler
.Priority priority
)
176 if (this.IsUpToDate (file
.FullName
))
179 // Try and parse a Note from the given path
180 Note note
= TomboyNote
.ParseNote (file
);
184 // A Note was returned; add it to the index
185 Indexable indexable
= NoteToIndexable (file
, note
);
187 Scheduler
.Task task
= NewAddTask (indexable
);
188 task
.Priority
= priority
;
189 task
.SubPriority
= 0;
190 ThisScheduler
.Add (task
);
194 private void RemoveNote (string file
)
196 Uri uri
= Note
.BuildNoteUri (file
, "tomboy");
197 Scheduler
.Task task
= NewRemoveTask (uri
);
198 task
.Priority
= Scheduler
.Priority
.Immediate
;
199 task
.SubPriority
= 0;
200 ThisScheduler
.Add (task
);
203 override protected void PostAddHook (Indexable indexable
, IndexerAddedReceipt receipt
)
205 base.PostAddHook (indexable
, receipt
);
207 // Store the note's text in the text cache.
208 // By doing this in the PostAddHook, we ensure that
209 // the TextCache is not modified until we are
210 // sure that the note was actually indexed.
212 text
= (string) note_text_cache
[receipt
.Uri
];
213 // If text == null, this is equivalent to
214 // calling Delete (receipt.Uri)
215 TextCache
.UserCache
.WriteFromString (receipt
.Uri
, text
);
216 note_text_cache
.Remove (receipt
.Uri
);
219 override protected bool HitIsValid (Uri uri
)
221 string note
= Path
.Combine (tomboy_dir
, uri
.Segments
[1] + ".note");
223 if (File
.Exists (note
))