Dont reindex already indexed files. Yet another bug uncovered by the DateTime fixes.
[beagle.git] / mozilla-extension / content / beagleOverlay.js
blob2a3971fc4fbfe26a79e02de592fe738642e1cf79
1 /* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\r
2 /*\r
3  * Beagle Extension: Index webpages you visit using the Beagle Indexing Engine.\r
4  * An Extension for the Firefox (and Mozilla?) Browser.\r
5  */\r
6 \r
7 // Initiate a new preference instance.\r
8 var gPref = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);\r
9 var gEnv = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment);\r
11 // Load jslib parts used in file execution\r
12 var gFile = new FileUtils();\r
14 // Create the global variables\r
15 var gBeagleRunStatus = 0;\r
16 var gBeagleDataPath = gEnv.get("HOME") + "/.beagle/ToIndex";\r
17 var gBeagleDataDir = new Dir(gBeagleDataPath);\r
18 var gBeagleBestPath;\r
20 function beagleFindFileInPath(filename)\r
21 {\r
22   var path = gEnv.get("PATH");\r
23   if (path) {\r
24     var split = path.split(':');\r
25     var idx = 0;\r
26     while (idx < split.length) {\r
27       var trypath = split[idx++] + '/' + filename;\r
28       if (gFile.exists(trypath))\r
29         return trypath;\r
30     }\r
31   }\r
32   return undefined;\r
33 }\r
35 function beagleInit()\r
36 {\r
37   dump ("beagleInit started!\n");\r
39   gBeagleBestPath = beagleFindFileInPath("beagle-search");\r
41   dump ("beagleInit: Found beagle-search: " + gBeagleBestPath + "\n");\r
43   // Create eventlistener to trigger when context menu is invoked.\r
44   if (gBeagleBestPath) {\r
45     try {\r
46       document.getElementById('contentAreaContextMenu').addEventListener('popupshowing',\r
47                                                                          beagleContext,\r
48                                                                          false);\r
49     } catch(e) {\r
50       alert(e);\r
51     }\r
52   }\r
54   // Get the global enable/disable pref\r
55   try { bPref = gPref.getBoolPref('beagle.enabled'); }\r
56   catch(e) { bPref = true }\r
58   if (bPref)\r
59     gBeagleRunStatus = 0;\r
60   else\r
61     gBeagleRunStatus = -1;\r
63   // Add listener for page loads\r
64   if (document.getElementById("appcontent"))\r
65     document.getElementById("appcontent").addEventListener("load", \r
66                                                            beaglePageLoad, \r
67                                                            true);\r
68   dump ("beagleInit : Listening to document['appcontent'].load\n");\r
70   beagleUpdateStatus ();\r
71 }\r
73 //\r
74 // Copied from nsIWebBrowserPersist.idl\r
75 //\r
77 // Only use cached data (could fail)\r
78 var PERSIST_FLAGS_FROM_CACHE = 1;\r
79 // Replace existing files on the disk\r
80 var PERSIST_FLAGS_REPLACE_EXISTING_FILES = 32;\r
81 // Don't modify or add base tags\r
82 var PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS = 64;\r
83 // Don't make any adjustments to links\r
84 var PERSIST_FLAGS_DONT_FIXUP_LINKS = 512;\r
85 // Don't make any adjustments to filenames\r
86 var PERSIST_FLAGS_DONT_CHANGE_FILENAMES = 2048;\r
87 // Cleanup on failure\r
88 var PERSIST_FLAGS_CLEANUP_ON_FAILURE = 8192;\r
90 var PERSIST_MASK = (PERSIST_FLAGS_FROM_CACHE | \r
91                     PERSIST_FLAGS_REPLACE_EXISTING_FILES |\r
92                     PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS |\r
93                     PERSIST_FLAGS_DONT_FIXUP_LINKS |\r
94                     PERSIST_FLAGS_DONT_CHANGE_FILENAMES |\r
95                     PERSIST_FLAGS_CLEANUP_ON_FAILURE);\r
97 // Write raw source\r
98 var ENCODE_FLAGS_RAW = 4;\r
99 // Convert links to absolute links where possible.\r
100 var ENCODE_FLAGS_ABSOLUTE_LINKS = 128;\r
102 var ENCODE_MASK = (ENCODE_FLAGS_RAW | ENCODE_FLAGS_ABSOLUTE_LINKS);\r
104 function beagleWriteContent(page, tmpfilepath)\r
106   var tmpfile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);\r
107   tmpfile.initWithPath(tmpfilepath);\r
109   var persist = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist);\r
110   persist.persistFlags = PERSIST_MASK;\r
112   persist.saveDocument(page, tmpfile, null, null, ENCODE_MASK, 0);\r
115 function beagleWriteMetadata(page, tmpfilepath)\r
117   var tmpfile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);\r
118   tmpfile.initWithPath(tmpfilepath);\r
120   var stream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);\r
121   stream.QueryInterface(Components.interfaces.nsIOutputStream);\r
122   stream.init(tmpfile, 0x04 | 0x08 | 0x20, 0600, 0);\r
124   var line;\r
126   // First line: URI\r
127   line = page.location.href + "\n";\r
128   stream.write(line, line.length);\r
129   \r
130   // Second line: Hit Type\r
131   line = "WebHistory\n";\r
132   stream.write(line, line.length);\r
134   // Third line: Mime type\r
135   line = "text/html\n";\r
136   stream.write(line, line.length);\r
138   // Additional lines: Properties\r
139   line = "k:_unindexed:encoding=" + page.characterSet + "\n";\r
140   stream.write(line, line.length);\r
142   stream.flush();\r
143   stream.close();\r
146 function beagleShouldIndex(page)\r
148   // user disabled, or can't find beagle-index-url.\r
149   if (gBeagleRunStatus == -1)\r
150     return false;\r
152   if (!page || \r
153       !page.location || \r
154       page.location == 'about:blank' || \r
155       !page.location.href) {\r
156     dump("beagleShouldIndex: strange page: " + page + "\n");\r
157     return false;\r
158   }\r
160   try {\r
161     fPref = gPref.getCharPref('beagle.security.filters');\r
162     var filtered = fPref.split(';');\r
163     for (j = 0; j < filtered.length; j++){\r
164       if (page.location.host.search("/"+filtered[j]+"/i") != -1){\r
165         dump("beagleShouldIndex: filtered host: " + page.location.host + '\n');\r
166         gBeagleRunStatus = -2;\r
167         beagleUpdateStatus ();\r
168         return false;\r
169       }\r
170     }\r
171   } catch (e) {\r
172     // Do nothing..\r
173   }\r
175   if (page.location.protocol == "https:") {\r
176         var bPref;\r
178         // secure content, check if user wants it indexed\r
179         try { bPref = gPref.getBoolPref('beagle.security.active'); }\r
180         catch(e) { bPref = false }\r
182         if (!bPref) {\r
183           // don't index. disable and return.\r
184           gBeagleRunStatus = -2;\r
185           beagleUpdateStatus ();\r
186           return false;\r
187         }\r
188   } else if (gBeagleRunStatus == -2) {\r
189         // no longer secure content, re-enable\r
190         gBeagleRunStatus = 0;\r
191         beagleUpdateStatus ();\r
192   }\r
193   \r
194   return true;\r
197 function beaglePageLoad(event)\r
199   var page = event.originalTarget;\r
201   if (!beagleShouldIndex (page))\r
202     return;\r
204   if (!gFile.exists (gEnv.get("HOME") + "/.beagle")) {\r
205     dump("beaglePageLoad: ~/.beagle doesn't exist, not indexing");\r
206     return;\r
207   }\r
209   dump("beaglePageLoad: storing page: " + page.location.href + "\n");\r
211   if (!gFile.exists(gBeagleDataPath)) {\r
212     try {\r
213       gBeagleDataDir.create ();\r
214       dump ("beaglePageLoad: Created .beagle/firefox\n");\r
215     } catch(e) {\r
216       dump ("beaglePageLoad: Unable to create .beagle/firefox: " + e + "\n");\r
217     }\r
218   }\r
220   var hash = hex_md5(page.location.href);\r
221   var tmpdatapath = gBeagleDataPath + "/firefox-beagle-" + hash + ".html";\r
222   var tmpmetapath = gBeagleDataPath + "/.firefox-beagle-" + hash + ".html";\r
224   try {\r
225     beagleWriteContent(page, tmpdatapath);\r
226     dump ("beaglePageLoad: beagleWriteContent sucessful!\n");\r
227     beagleWriteMetadata(page, tmpmetapath);\r
228     dump ("beaglePageLoad: beagleWriteMetadata sucessful!\n");\r
229   } catch (ex) {\r
230     alert ("beaglePageLoad: beagleWriteContent/Metadata failed: " + ex);\r
231   }\r
234 function beagleRunBest(query)\r
236   try {\r
237     dump("Running best with query: "+ query + "\n");\r
238     var retval = gFile.spawn(gBeagleBestPath, ["", query]);\r
239     if (retval) \r
240       alert("Error running best: " + retval);\r
241   } catch(e) {\r
242     alert("Caught error from best: " + e);\r
243   }\r
246 function beagleShowPrefs()\r
248   window.openDialog('chrome://beagle/content/beaglePrefs.xul',\r
249                     'PrefWindow',\r
250                     'chrome,modal=yes,resizable=no',\r
251                     'browser');\r
254 function beagleProcessClick(event)\r
256   // Right-click event.\r
257   if (event.button == 2) {\r
258     beagleShowPrefs();\r
259     return;\r
260   }\r
262   // Left-click event (also single click, like Mac).\r
263   if (event.button == 0) {\r
264     if (event.ctrlKey) {\r
265       // Ctrl-click for Mac properties.  Works on PC too.\r
266       beagleShowPrefs();\r
267     } else {\r
268       switch(gBeagleRunStatus) {\r
269       case 0:\r
270         // currently enabled. disable by user.\r
271         gBeagleRunStatus = -1;\r
272         gPref.setBoolPref('beagle.enabled', false);\r
273         break;\r
274       case -1:\r
275       case -2:\r
276         // currently disabled (by user or by secure content). enable.\r
277         gBeagleRunStatus = 0;\r
278         gPref.setBoolPref('beagle.enabled', true);\r
279         break;\r
280       default:\r
281         // last run was an error, show the error\r
282         alert("Error running Beagle Indexer: " + gBeagleRunStatus);\r
283         return;\r
284       }\r
286       beagleUpdateStatus();\r
287     }\r
288   }\r
291 function beagleUpdateStatus()\r
293   var icon = document.getElementById('beagle-notifier-status');\r
295   switch(gBeagleRunStatus) {\r
296     case 0: // active\r
297       icon.setAttribute("status","000");\r
298       icon.setAttribute("tooltiptext","Beagle indexing active. Click to disable.");\r
299       break;\r
300     case -1: // disabled by user\r
301     case -2: // disabled for secure protocol\r
302       icon.setAttribute("status","00f");\r
303       icon.setAttribute("tooltiptext","Beagle indexing disabled.  Click to enable.");\r
304       break;\r
305     default: // anything else is an error\r
306       icon.setAttribute("status","f00");\r
307       icon.setAttribute("tooltiptext",\r
308                         "Error while indexing: " + gBeagleRunStatus);\r
309       break;\r
310   }\r
313 // Create event listener.\r
314 window.addEventListener('load', beagleInit, false); \r
316 // Right-click context menu\r
317 function beagleContext()\r
319   var bPref;\r
321   // Find context menu display preference.\r
322   try      { bPref = gPref.getBoolPref('beagle.context.active'); }\r
323   catch(e) { }\r
325   // Set hidden property of context menu and separators.\r
326   document.getElementById('beagle-context-menu').hidden = !(bPref);\r
327   document.getElementById('beagle-context-sep-a').hidden = !(bPref);\r
328   document.getElementById('beagle-context-sep-b').hidden = !(bPref);\r
330   // If not displaying context menu, return.\r
331   if (!bPref) return;\r
333   // Separator A (top) display preference.\r
334   try      { bPref = gPref.getBoolPref('beagle.context.sep.a'); }\r
335   catch(e) { bPref = false }\r
336   document.getElementById('beagle-context-sep-a').hidden = !(bPref);\r
338   // Separator B (bottom) display preference.\r
339   try      { bPref = gPref.getBoolPref('beagle.context.sep.b'); }\r
340   catch(e) { bPref = false }\r
341   document.getElementById('beagle-context-sep-b').hidden = !(bPref);\r
343   // Should search link item be hidden or shown?\r
344   document.getElementById('beagle-context-search-link').hidden = !(gContextMenu.onLink);\r
346   // Should text search item be hidden or shown?\r
347   document.getElementById('beagle-context-search-text').hidden = !(gContextMenu.isTextSelected);\r
348   document.getElementById('beagle-context-search-text').setAttribute("label","Search for \"" + gContextMenu.searchSelected() + "\"");\r