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
;
30 using System
.Threading
;
33 using System
.Xml
.Serialization
;
38 namespace Beagle
.Daemon
.BlamQueryable
{
40 [QueryableFlavor (Name
="Blam", Domain
=QueryDomain
.Local
, RequireInotify
=false)]
41 public class BlamQueryable
: LuceneFileQueryable
, IIndexableGenerator
{
43 private static Logger log
= Logger
.Get ("BlamQueryable");
48 public BlamQueryable () : base ("BlamIndex")
50 blam_dir
= Path
.Combine (Path
.Combine (PathFinder
.HomeDir
, ".gnome2"), "blam");
51 blam_file
= new FileInfo (Path
.Combine (blam_dir
, "collection.xml"));
54 /////////////////////////////////////////////////
56 public override void Start ()
60 ExceptionHandlingThread
.Start (new ThreadStart (StartWorker
));
63 private void StartWorker ()
65 if (!Directory
.Exists (blam_dir
)) {
66 GLib
.Timeout
.Add (60000, new GLib
.TimeoutHandler (CheckForExistence
));
70 if (Inotify
.Enabled
) {
71 Inotify
.EventType mask
= Inotify
.EventType
.CloseWrite
;
72 Inotify
.Subscribe (blam_dir
, OnInotifyEvent
, mask
);
74 FileSystemWatcher fsw
= new FileSystemWatcher ();
76 fsw
.Filter
= blam_file
.Name
;
78 fsw
.Changed
+= new FileSystemEventHandler (OnChangedEvent
);
79 fsw
.Created
+= new FileSystemEventHandler (OnChangedEvent
);
81 fsw
.EnableRaisingEvents
= true;
84 if (File
.Exists (blam_file
.FullName
))
88 private bool CheckForExistence ()
90 if (!Directory
.Exists (blam_dir
))
98 /////////////////////////////////////////////////
100 // Modified event using Inotify
101 private void OnInotifyEvent (Inotify
.Watch watch
,
105 Inotify
.EventType type
)
107 if (subitem
!= blam_file
.Name
)
113 // Modified/Created event using FSW
114 private void OnChangedEvent (object o
, FileSystemEventArgs args
)
119 /////////////////////////////////////////////////
121 private void Index ()
123 log
.Debug ("Creating blam indexable generator");
124 Scheduler
.Task task
= NewAddTask (this);
126 ThisScheduler
.Add (task
);
129 /////////////////////////////////////////////////
131 // IIndexableGenerator implementation
133 private ChannelCollection collection
= null;
134 private IEnumerator channel_enumerator
= null;
135 private IEnumerator item_enumerator
= null;
137 public Indexable
GetNextIndexable ()
139 Channel channel
= (Channel
) this.channel_enumerator
.Current
;
140 Item item
= (Item
) this.item_enumerator
.Current
;
142 Uri uri
= new Uri (String
.Format ("feed:{0};item={1}", channel
.Url
, item
.Id
));
144 Indexable indexable
= new Indexable (uri
);
145 indexable
.ParentUri
= UriFu
.PathToFileUri (blam_file
.FullName
);
146 indexable
.MimeType
= "text/html";
147 indexable
.Type
= "FeedItem";
148 indexable
.Timestamp
= item
.PubDate
;
150 indexable
.AddProperty (Property
.New ("dc:title", item
.Title
));
151 indexable
.AddProperty (Property
.New ("fixme:author", item
.Author
));
152 indexable
.AddProperty (Property
.NewDate ("fixme:published", item
.PubDate
));
153 indexable
.AddProperty (Property
.NewKeyword ("fixme:itemuri", item
.Link
));
154 indexable
.AddProperty (Property
.NewKeyword ("fixme:webloguri", channel
.Url
));
157 int i
= item
.Text
.IndexOf ("<img src=\"");
159 i
+= "<img src=\"".Length
;
160 int j
= item
.Text
.IndexOf ("\"", i
);
162 img
= item
.Text
.Substring (i
, j
-i
);
166 string path
= Path
.Combine (Path
.Combine (blam_dir
, "Cache"),
167 img
.GetHashCode ().ToString ());
168 indexable
.AddProperty (Property
.NewUnsearched ("fixme:cachedimg", path
));
171 StringReader reader
= new StringReader (item
.Text
);
172 indexable
.SetTextReader (reader
);
177 public bool HasNextIndexable ()
179 if (this.collection
== null) {
180 if (IsUpToDate (blam_file
.FullName
))
184 this.collection
= ChannelCollection
.LoadFromFile (blam_file
.FullName
);
185 } catch (Exception e
) {
186 log
.Warn ("Could not open Blam! channel list: " + e
);
190 if (this.collection
.Channels
== null || this.collection
.Channels
.Count
== 0) {
191 this.collection
= null;
195 this.channel_enumerator
= this.collection
.Channels
.GetEnumerator ();
198 while (this.item_enumerator
== null || !this.item_enumerator
.MoveNext ()) {
202 if (!this.channel_enumerator
.MoveNext ()) {
203 this.collection
= null;
204 this.channel_enumerator
= null;
208 channel
= (Channel
) this.channel_enumerator
.Current
;
209 } while (channel
.Items
== null || channel
.Items
.Count
== 0);
211 this.item_enumerator
= channel
.Items
.GetEnumerator ();
217 public string StatusName
{
222 /////////////////////////////////////////////////
224 // Classes from Blam! sources for deserialization
226 public class ChannelCollection
{
228 private ArrayList mChannels
;
230 [XmlElement ("Channel", typeof (Channel
))]
231 public ArrayList Channels
{
232 get { return mChannels; }
233 set { mChannels = value; }
236 public static ChannelCollection
LoadFromFile (string filename
)
238 XmlSerializer serializer
= new XmlSerializer (typeof (ChannelCollection
));
239 ChannelCollection collection
;
241 Stream stream
= new FileStream (filename
,
244 FileShare
.ReadWrite
);
245 XmlTextReader reader
= new XmlTextReader (stream
);
247 collection
= (ChannelCollection
) serializer
.Deserialize (reader
);
257 [XmlAttribute
] public string Name
= "";
258 [XmlAttribute
] public string Url
= "";
260 [XmlAttribute
] public string LastModified
= "";
261 [XmlAttribute
] public string ETag
= "";
265 [XmlElement ("Item", typeof (Item
))]
266 public ArrayList Items
{
267 get { return mItems; }
268 set { mItems = value; }
274 [XmlAttribute
] public string Id
= "";
275 [XmlAttribute
] public bool Unread
= true;
276 [XmlAttribute
] public string Title
= "";
277 [XmlAttribute
] public string Text
= "";
278 [XmlAttribute
] public string Link
= "";
279 [XmlAttribute
] public DateTime PubDate
;
280 [XmlAttribute
] public string Author
= "";