4 // Copyright (C) 2005 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.
28 using System
.Collections
;
31 using System
.Threading
;
36 namespace Beagle
.Daemon
.KopeteQueryable
{
38 [QueryableFlavor (Name
="Kopete", Domain
=QueryDomain
.Local
, RequireInotify
=false)]
39 public class KopeteQueryable
: LuceneFileQueryable
{
41 private string config_dir
, log_dir
;
43 private int polling_interval_in_seconds
= 60;
45 private KopeteCrawler crawler
;
47 private KopeteBuddyListReader list
= new KopeteBuddyListReader ();
49 public KopeteQueryable () : base ("KopeteIndex")
51 config_dir
= Path
.Combine (PathFinder
.HomeDir
, ".kde/share/apps/kopete");
52 log_dir
= Path
.Combine (config_dir
, "logs");
55 /////////////////////////////////////////////////
57 private void StartWorker()
59 if (! Directory
.Exists (log_dir
)) {
60 GLib
.Timeout
.Add (60000, new GLib
.TimeoutHandler (CheckForExistence
));
64 Logger
.Log
.Info ("Starting Kopete log backend");
66 Stopwatch stopwatch
= new Stopwatch ();
72 crawler
= new KopeteCrawler (log_dir
);
75 if (!Inotify
.Enabled
) {
76 Scheduler
.Task task
= Scheduler
.TaskFromHook (new Scheduler
.TaskHook (CrawlHook
));
77 task
.Tag
= "Crawling ~/.kopete/logs to find new logfiles";
78 ThisScheduler
.Add (task
);
83 Logger
.Log
.Info ("Kopete log backend worker thread done in {0}", stopwatch
);
86 public override void Start ()
90 ExceptionHandlingThread
.Start (new ThreadStart (StartWorker
));
93 /////////////////////////////////////////////////
98 foreach (FileInfo file
in crawler
.Logs
) {
99 IndexLog (file
.FullName
, Scheduler
.Priority
.Delayed
);
103 private void CrawlHook (Scheduler
.Task task
)
106 task
.Reschedule
= true;
107 task
.TriggerTime
= DateTime
.Now
.AddSeconds (polling_interval_in_seconds
);
110 /////////////////////////////////////////////////
112 // Sets up an Inotify watch on all subdirectories withing ~/.kopete/logs
113 private void Watch (string path
)
115 DirectoryInfo root
= new DirectoryInfo (path
);
120 Queue queue
= new Queue ();
121 queue
.Enqueue (root
);
123 while (queue
.Count
> 0) {
124 DirectoryInfo dir
= queue
.Dequeue () as DirectoryInfo
;
126 // Setup watches on the present directory.
127 Inotify
.Subscribe (dir
.FullName
, OnInotifyEvent
,
128 Inotify
.EventType
.Create
| Inotify
.EventType
.CloseWrite
);
130 // Add all subdirectories to the queue so their files can be indexed.
131 foreach (DirectoryInfo subdir
in dir
.GetDirectories ())
132 queue
.Enqueue (subdir
);
136 /////////////////////////////////////////////////
138 private bool CheckForExistence ()
140 if (!Directory
.Exists (log_dir
))
148 /////////////////////////////////////////////////
150 private void OnInotifyEvent (Inotify
.Watch watch
,
154 Inotify
.EventType type
)
159 string full_path
= Path
.Combine (path
, subitem
);
161 if ((type
& Inotify
.EventType
.Create
) != 0 && (type
& Inotify
.EventType
.IsDirectory
) != 0) {
166 if ((type
& Inotify
.EventType
.Modify
) != 0) {
167 IndexLog (full_path
, Scheduler
.Priority
.Immediate
);
172 /////////////////////////////////////////////////
174 private static Indexable
ImLogToIndexable (ImLog log
)
176 Indexable indexable
= new Indexable (log
.Uri
);
177 indexable
.Timestamp
= log
.Timestamp
;
178 indexable
.MimeType
= "text/plain";
179 indexable
.Type
= "IMLog";
181 StringBuilder text
= new StringBuilder ();
182 foreach (ImLog
.Utterance utt
in log
.Utterances
) {
183 //Console.WriteLine ("[{0}][{1}]", utt.Who, utt.Text);
184 text
.Append (utt
.Text
);
188 indexable
.AddProperty (Property
.NewKeyword ("fixme:file", log
.LogFile
));
189 indexable
.AddProperty (Property
.NewKeyword ("fixme:offset", log
.LogOffset
));
190 indexable
.AddProperty (Property
.NewDate ("fixme:starttime", log
.StartTime
));
191 indexable
.AddProperty (Property
.NewKeyword ("fixme:speakingto", log
.SpeakingTo
));
192 indexable
.AddProperty (Property
.NewKeyword ("fixme:identity", log
.Identity
));
193 indexable
.AddProperty (Property
.NewDate ("fixme:endtime", log
.EndTime
));
195 indexable
.AddProperty (Property
.New ("fixme:client", log
.Client
));
196 indexable
.AddProperty (Property
.New ("fixme:protocol", log
.Protocol
));
198 StringReader reader
= new StringReader (text
.ToString ());
199 indexable
.SetTextReader (reader
);
204 private void IndexLog (string filename
, Scheduler
.Priority priority
)
206 FileInfo info
= new FileInfo (filename
);
210 if (IsUpToDate (filename
))
213 ICollection logs
= KopeteLog
.ScanLog (info
);
214 foreach (ImLog log
in logs
) {
215 Indexable indexable
= ImLogToIndexable (log
);
216 Scheduler
.Task task
= NewAddTask (indexable
);
217 task
.Priority
= priority
;
218 task
.SubPriority
= 0;
219 ThisScheduler
.Add (task
);
223 override protected double RelevancyMultiplier (Hit hit
)
225 return HalfLifeMultiplierFromProperty (hit
, 0.25,
226 "fixme:endtime", "fixme:starttime");
229 override public string GetSnippet (string[] query_terms
, Hit hit
)
231 // FIXME: This does the wrong thing for old-style logs.
232 string file
= hit
["fixme:file"];
233 ICollection logs
= KopeteLog
.ScanLog (new FileInfo (file
));
234 IEnumerator iter
= logs
.GetEnumerator ();
236 if (iter
.MoveNext ())
237 log
= iter
.Current
as ImLog
;
243 // FIXME: This is very lame, and doesn't do the
244 // right thing w/ stemming, word boundaries, etc.
245 foreach (ImLog
.Utterance utt
in log
.Utterances
) {
246 string text
= utt
.Text
;
247 string who
= utt
.Who
;
249 string snippet
= SnippetFu
.GetSnippet (query_terms
, new StringReader (text
));
251 if (snippet
== null || snippet
== "")
254 result
+= String
.Format ("{0}: {1} ", who
, snippet
);
256 if (result
.Length
> 300)
266 override protected bool HitFilter (Hit hit
)
268 ImBuddy buddy
= list
.Search (hit
["fixme:speakingto"]);
271 if (buddy
.Alias
!= "")
272 hit
["fixme:speakingto_alias"] = buddy
.Alias
;