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