|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
6 Components.utils.import("resource://gre/modules/Services.jsm"); |
|
7 |
|
8 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", |
|
9 "resource://gre/modules/PrivateBrowsingUtils.jsm"); |
|
10 XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", |
|
11 "resource:///modules/RecentWindow.jsm"); |
|
12 |
|
13 const nsISupports = Components.interfaces.nsISupports; |
|
14 |
|
15 const nsIBrowserDOMWindow = Components.interfaces.nsIBrowserDOMWindow; |
|
16 const nsIBrowserHandler = Components.interfaces.nsIBrowserHandler; |
|
17 const nsIBrowserHistory = Components.interfaces.nsIBrowserHistory; |
|
18 const nsIChannel = Components.interfaces.nsIChannel; |
|
19 const nsICommandLine = Components.interfaces.nsICommandLine; |
|
20 const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler; |
|
21 const nsIContentHandler = Components.interfaces.nsIContentHandler; |
|
22 const nsIDocShellTreeItem = Components.interfaces.nsIDocShellTreeItem; |
|
23 const nsIDOMChromeWindow = Components.interfaces.nsIDOMChromeWindow; |
|
24 const nsIDOMWindow = Components.interfaces.nsIDOMWindow; |
|
25 const nsIFileURL = Components.interfaces.nsIFileURL; |
|
26 const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor; |
|
27 const nsINetUtil = Components.interfaces.nsINetUtil; |
|
28 const nsIPrefBranch = Components.interfaces.nsIPrefBranch; |
|
29 const nsIPrefLocalizedString = Components.interfaces.nsIPrefLocalizedString; |
|
30 const nsISupportsString = Components.interfaces.nsISupportsString; |
|
31 const nsIURIFixup = Components.interfaces.nsIURIFixup; |
|
32 const nsIWebNavigation = Components.interfaces.nsIWebNavigation; |
|
33 const nsIWindowMediator = Components.interfaces.nsIWindowMediator; |
|
34 const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher; |
|
35 const nsIWebNavigationInfo = Components.interfaces.nsIWebNavigationInfo; |
|
36 const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService; |
|
37 const nsICommandLineValidator = Components.interfaces.nsICommandLineValidator; |
|
38 |
|
39 const NS_BINDING_ABORTED = Components.results.NS_BINDING_ABORTED; |
|
40 const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001; |
|
41 const NS_ERROR_ABORT = Components.results.NS_ERROR_ABORT; |
|
42 |
|
43 const URI_INHERITS_SECURITY_CONTEXT = Components.interfaces.nsIHttpProtocolHandler |
|
44 .URI_INHERITS_SECURITY_CONTEXT; |
|
45 |
|
46 function shouldLoadURI(aURI) { |
|
47 if (aURI && !aURI.schemeIs("chrome")) |
|
48 return true; |
|
49 |
|
50 dump("*** Preventing external load of chrome: URI into browser window\n"); |
|
51 dump(" Use -chrome <uri> instead\n"); |
|
52 return false; |
|
53 } |
|
54 |
|
55 function resolveURIInternal(aCmdLine, aArgument) { |
|
56 var uri = aCmdLine.resolveURI(aArgument); |
|
57 var urifixup = Components.classes["@mozilla.org/docshell/urifixup;1"] |
|
58 .getService(nsIURIFixup); |
|
59 |
|
60 if (!(uri instanceof nsIFileURL)) { |
|
61 return urifixup.createFixupURI(aArgument, |
|
62 urifixup.FIXUP_FLAG_FIX_SCHEME_TYPOS); |
|
63 } |
|
64 |
|
65 try { |
|
66 if (uri.file.exists()) |
|
67 return uri; |
|
68 } |
|
69 catch (e) { |
|
70 Components.utils.reportError(e); |
|
71 } |
|
72 |
|
73 // We have interpreted the argument as a relative file URI, but the file |
|
74 // doesn't exist. Try URI fixup heuristics: see bug 290782. |
|
75 |
|
76 try { |
|
77 uri = urifixup.createFixupURI(aArgument, 0); |
|
78 } |
|
79 catch (e) { |
|
80 Components.utils.reportError(e); |
|
81 } |
|
82 |
|
83 return uri; |
|
84 } |
|
85 |
|
86 var gFirstWindow = false; |
|
87 |
|
88 const OVERRIDE_NONE = 0; |
|
89 const OVERRIDE_NEW_PROFILE = 1; |
|
90 const OVERRIDE_NEW_MSTONE = 2; |
|
91 const OVERRIDE_NEW_BUILD_ID = 3; |
|
92 /** |
|
93 * Determines whether a home page override is needed. |
|
94 * Returns: |
|
95 * OVERRIDE_NEW_PROFILE if this is the first run with a new profile. |
|
96 * OVERRIDE_NEW_MSTONE if this is the first run with a build with a different |
|
97 * Gecko milestone (i.e. right after an upgrade). |
|
98 * OVERRIDE_NEW_BUILD_ID if this is the first run with a new build ID of the |
|
99 * same Gecko milestone (i.e. after a nightly upgrade). |
|
100 * OVERRIDE_NONE otherwise. |
|
101 */ |
|
102 function needHomepageOverride(prefb) { |
|
103 var savedmstone = null; |
|
104 try { |
|
105 savedmstone = prefb.getCharPref("browser.startup.homepage_override.mstone"); |
|
106 } catch (e) {} |
|
107 |
|
108 if (savedmstone == "ignore") |
|
109 return OVERRIDE_NONE; |
|
110 |
|
111 var mstone = Services.appinfo.platformVersion; |
|
112 |
|
113 var savedBuildID = null; |
|
114 try { |
|
115 savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID"); |
|
116 } catch (e) {} |
|
117 |
|
118 var buildID = Services.appinfo.platformBuildID; |
|
119 |
|
120 if (mstone != savedmstone) { |
|
121 // Bug 462254. Previous releases had a default pref to suppress the EULA |
|
122 // agreement if the platform's installer had already shown one. Now with |
|
123 // about:rights we've removed the EULA stuff and default pref, but we need |
|
124 // a way to make existing profiles retain the default that we removed. |
|
125 if (savedmstone) |
|
126 prefb.setBoolPref("browser.rights.3.shown", true); |
|
127 |
|
128 prefb.setCharPref("browser.startup.homepage_override.mstone", mstone); |
|
129 prefb.setCharPref("browser.startup.homepage_override.buildID", buildID); |
|
130 return (savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE); |
|
131 } |
|
132 |
|
133 if (buildID != savedBuildID) { |
|
134 prefb.setCharPref("browser.startup.homepage_override.buildID", buildID); |
|
135 return OVERRIDE_NEW_BUILD_ID; |
|
136 } |
|
137 |
|
138 return OVERRIDE_NONE; |
|
139 } |
|
140 |
|
141 /** |
|
142 * Gets the override page for the first run after the application has been |
|
143 * updated. |
|
144 * @param defaultOverridePage |
|
145 * The default override page. |
|
146 * @return The override page. |
|
147 */ |
|
148 function getPostUpdateOverridePage(defaultOverridePage) { |
|
149 var um = Components.classes["@mozilla.org/updates/update-manager;1"] |
|
150 .getService(Components.interfaces.nsIUpdateManager); |
|
151 try { |
|
152 // If the updates.xml file is deleted then getUpdateAt will throw. |
|
153 var update = um.getUpdateAt(0) |
|
154 .QueryInterface(Components.interfaces.nsIPropertyBag); |
|
155 } catch (e) { |
|
156 // This should never happen. |
|
157 Components.utils.reportError("Unable to find update: " + e); |
|
158 return defaultOverridePage; |
|
159 } |
|
160 |
|
161 let actions = update.getProperty("actions"); |
|
162 // When the update doesn't specify actions fallback to the original behavior |
|
163 // of displaying the default override page. |
|
164 if (!actions) |
|
165 return defaultOverridePage; |
|
166 |
|
167 // The existence of silent or the non-existence of showURL in the actions both |
|
168 // mean that an override page should not be displayed. |
|
169 if (actions.indexOf("silent") != -1 || actions.indexOf("showURL") == -1) |
|
170 return ""; |
|
171 |
|
172 return update.getProperty("openURL") || defaultOverridePage; |
|
173 } |
|
174 |
|
175 // Flag used to indicate that the arguments to openWindow can be passed directly. |
|
176 const NO_EXTERNAL_URIS = 1; |
|
177 |
|
178 function openWindow(parent, url, target, features, args, noExternalArgs) { |
|
179 var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] |
|
180 .getService(nsIWindowWatcher); |
|
181 |
|
182 if (noExternalArgs == NO_EXTERNAL_URIS) { |
|
183 // Just pass in the defaultArgs directly |
|
184 var argstring; |
|
185 if (args) { |
|
186 argstring = Components.classes["@mozilla.org/supports-string;1"] |
|
187 .createInstance(nsISupportsString); |
|
188 argstring.data = args; |
|
189 } |
|
190 |
|
191 return wwatch.openWindow(parent, url, target, features, argstring); |
|
192 } |
|
193 |
|
194 // Pass an array to avoid the browser "|"-splitting behavior. |
|
195 var argArray = Components.classes["@mozilla.org/supports-array;1"] |
|
196 .createInstance(Components.interfaces.nsISupportsArray); |
|
197 |
|
198 // add args to the arguments array |
|
199 var stringArgs = null; |
|
200 if (args instanceof Array) // array |
|
201 stringArgs = args; |
|
202 else if (args) // string |
|
203 stringArgs = [args]; |
|
204 |
|
205 if (stringArgs) { |
|
206 // put the URIs into argArray |
|
207 var uriArray = Components.classes["@mozilla.org/supports-array;1"] |
|
208 .createInstance(Components.interfaces.nsISupportsArray); |
|
209 stringArgs.forEach(function (uri) { |
|
210 var sstring = Components.classes["@mozilla.org/supports-string;1"] |
|
211 .createInstance(nsISupportsString); |
|
212 sstring.data = uri; |
|
213 uriArray.AppendElement(sstring); |
|
214 }); |
|
215 argArray.AppendElement(uriArray); |
|
216 } else { |
|
217 argArray.AppendElement(null); |
|
218 } |
|
219 |
|
220 // Pass these as null to ensure that we always trigger the "single URL" |
|
221 // behavior in browser.js's gBrowserInit.onLoad (which handles the window |
|
222 // arguments) |
|
223 argArray.AppendElement(null); // charset |
|
224 argArray.AppendElement(null); // referer |
|
225 argArray.AppendElement(null); // postData |
|
226 argArray.AppendElement(null); // allowThirdPartyFixup |
|
227 |
|
228 return wwatch.openWindow(parent, url, target, features, argArray); |
|
229 } |
|
230 |
|
231 function openPreferences() { |
|
232 if (Services.prefs.getBoolPref("browser.preferences.inContent")) { |
|
233 var sa = Components.classes["@mozilla.org/supports-array;1"] |
|
234 .createInstance(Components.interfaces.nsISupportsArray); |
|
235 |
|
236 var wuri = Components.classes["@mozilla.org/supports-string;1"] |
|
237 .createInstance(Components.interfaces.nsISupportsString); |
|
238 wuri.data = "about:preferences"; |
|
239 |
|
240 sa.AppendElement(wuri); |
|
241 |
|
242 var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] |
|
243 .getService(nsIWindowWatcher); |
|
244 |
|
245 wwatch.openWindow(null, gBrowserContentHandler.chromeURL, |
|
246 "_blank", |
|
247 "chrome,dialog=no,all", |
|
248 sa); |
|
249 } else { |
|
250 var features = "chrome,titlebar,toolbar,centerscreen,dialog=no"; |
|
251 var url = "chrome://browser/content/preferences/preferences.xul"; |
|
252 |
|
253 var win = getMostRecentWindow("Browser:Preferences"); |
|
254 if (win) { |
|
255 win.focus(); |
|
256 } else { |
|
257 openWindow(null, url, "_blank", features); |
|
258 } |
|
259 } |
|
260 } |
|
261 |
|
262 function getMostRecentWindow(aType) { |
|
263 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] |
|
264 .getService(nsIWindowMediator); |
|
265 return wm.getMostRecentWindow(aType); |
|
266 } |
|
267 |
|
268 function doSearch(searchTerm, cmdLine) { |
|
269 var ss = Components.classes["@mozilla.org/browser/search-service;1"] |
|
270 .getService(nsIBrowserSearchService); |
|
271 |
|
272 var submission = ss.defaultEngine.getSubmission(searchTerm); |
|
273 |
|
274 // fill our nsISupportsArray with uri-as-wstring, null, null, postData |
|
275 var sa = Components.classes["@mozilla.org/supports-array;1"] |
|
276 .createInstance(Components.interfaces.nsISupportsArray); |
|
277 |
|
278 var wuri = Components.classes["@mozilla.org/supports-string;1"] |
|
279 .createInstance(Components.interfaces.nsISupportsString); |
|
280 wuri.data = submission.uri.spec; |
|
281 |
|
282 sa.AppendElement(wuri); |
|
283 sa.AppendElement(null); |
|
284 sa.AppendElement(null); |
|
285 sa.AppendElement(submission.postData); |
|
286 |
|
287 // XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing |
|
288 // preferences, but need nsIBrowserDOMWindow extensions |
|
289 |
|
290 var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] |
|
291 .getService(nsIWindowWatcher); |
|
292 |
|
293 return wwatch.openWindow(null, gBrowserContentHandler.chromeURL, |
|
294 "_blank", |
|
295 "chrome,dialog=no,all" + |
|
296 gBrowserContentHandler.getFeatures(cmdLine), |
|
297 sa); |
|
298 } |
|
299 |
|
300 function nsBrowserContentHandler() { |
|
301 } |
|
302 nsBrowserContentHandler.prototype = { |
|
303 classID: Components.ID("{5d0ce354-df01-421a-83fb-7ead0990c24e}"), |
|
304 |
|
305 _xpcom_factory: { |
|
306 createInstance: function bch_factory_ci(outer, iid) { |
|
307 if (outer) |
|
308 throw Components.results.NS_ERROR_NO_AGGREGATION; |
|
309 return gBrowserContentHandler.QueryInterface(iid); |
|
310 } |
|
311 }, |
|
312 |
|
313 /* helper functions */ |
|
314 |
|
315 mChromeURL : null, |
|
316 |
|
317 get chromeURL() { |
|
318 if (this.mChromeURL) { |
|
319 return this.mChromeURL; |
|
320 } |
|
321 |
|
322 var prefb = Components.classes["@mozilla.org/preferences-service;1"] |
|
323 .getService(nsIPrefBranch); |
|
324 this.mChromeURL = prefb.getCharPref("browser.chromeURL"); |
|
325 |
|
326 return this.mChromeURL; |
|
327 }, |
|
328 |
|
329 /* nsISupports */ |
|
330 QueryInterface : XPCOMUtils.generateQI([nsICommandLineHandler, |
|
331 nsIBrowserHandler, |
|
332 nsIContentHandler, |
|
333 nsICommandLineValidator]), |
|
334 |
|
335 /* nsICommandLineHandler */ |
|
336 handle : function bch_handle(cmdLine) { |
|
337 if (cmdLine.handleFlag("browser", false)) { |
|
338 // Passing defaultArgs, so use NO_EXTERNAL_URIS |
|
339 openWindow(null, this.chromeURL, "_blank", |
|
340 "chrome,dialog=no,all" + this.getFeatures(cmdLine), |
|
341 this.defaultArgs, NO_EXTERNAL_URIS); |
|
342 cmdLine.preventDefault = true; |
|
343 } |
|
344 |
|
345 try { |
|
346 var remoteCommand = cmdLine.handleFlagWithParam("remote", true); |
|
347 } |
|
348 catch (e) { |
|
349 throw NS_ERROR_ABORT; |
|
350 } |
|
351 |
|
352 if (remoteCommand != null) { |
|
353 try { |
|
354 var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand); |
|
355 var remoteVerb; |
|
356 if (a) { |
|
357 remoteVerb = a[1].toLowerCase(); |
|
358 var remoteParams = []; |
|
359 var sepIndex = a[2].lastIndexOf(","); |
|
360 if (sepIndex == -1) |
|
361 remoteParams[0] = a[2]; |
|
362 else { |
|
363 remoteParams[0] = a[2].substring(0, sepIndex); |
|
364 remoteParams[1] = a[2].substring(sepIndex + 1); |
|
365 } |
|
366 } |
|
367 |
|
368 switch (remoteVerb) { |
|
369 case "openurl": |
|
370 case "openfile": |
|
371 // openURL(<url>) |
|
372 // openURL(<url>,new-window) |
|
373 // openURL(<url>,new-tab) |
|
374 |
|
375 // First param is the URL, second param (if present) is the "target" |
|
376 // (tab, window) |
|
377 var url = remoteParams[0]; |
|
378 var target = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW; |
|
379 if (remoteParams[1]) { |
|
380 var targetParam = remoteParams[1].toLowerCase() |
|
381 .replace(/^\s*|\s*$/g, ""); |
|
382 if (targetParam == "new-tab") |
|
383 target = nsIBrowserDOMWindow.OPEN_NEWTAB; |
|
384 else if (targetParam == "new-window") |
|
385 target = nsIBrowserDOMWindow.OPEN_NEWWINDOW; |
|
386 else { |
|
387 // The "target" param isn't one of our supported values, so |
|
388 // assume it's part of a URL that contains commas. |
|
389 url += "," + remoteParams[1]; |
|
390 } |
|
391 } |
|
392 |
|
393 var uri = resolveURIInternal(cmdLine, url); |
|
394 handURIToExistingBrowser(uri, target, cmdLine); |
|
395 break; |
|
396 |
|
397 case "xfedocommand": |
|
398 // xfeDoCommand(openBrowser) |
|
399 if (remoteParams[0].toLowerCase() != "openbrowser") |
|
400 throw NS_ERROR_ABORT; |
|
401 |
|
402 // Passing defaultArgs, so use NO_EXTERNAL_URIS |
|
403 openWindow(null, this.chromeURL, "_blank", |
|
404 "chrome,dialog=no,all" + this.getFeatures(cmdLine), |
|
405 this.defaultArgs, NO_EXTERNAL_URIS); |
|
406 break; |
|
407 |
|
408 default: |
|
409 // Somebody sent us a remote command we don't know how to process: |
|
410 // just abort. |
|
411 throw "Unknown remote command."; |
|
412 } |
|
413 |
|
414 cmdLine.preventDefault = true; |
|
415 } |
|
416 catch (e) { |
|
417 Components.utils.reportError(e); |
|
418 // If we had a -remote flag but failed to process it, throw |
|
419 // NS_ERROR_ABORT so that the xremote code knows to return a failure |
|
420 // back to the handling code. |
|
421 throw NS_ERROR_ABORT; |
|
422 } |
|
423 } |
|
424 |
|
425 var uriparam; |
|
426 try { |
|
427 while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) { |
|
428 var uri = resolveURIInternal(cmdLine, uriparam); |
|
429 if (!shouldLoadURI(uri)) |
|
430 continue; |
|
431 openWindow(null, this.chromeURL, "_blank", |
|
432 "chrome,dialog=no,all" + this.getFeatures(cmdLine), |
|
433 uri.spec); |
|
434 cmdLine.preventDefault = true; |
|
435 } |
|
436 } |
|
437 catch (e) { |
|
438 Components.utils.reportError(e); |
|
439 } |
|
440 |
|
441 try { |
|
442 while ((uriparam = cmdLine.handleFlagWithParam("new-tab", false))) { |
|
443 var uri = resolveURIInternal(cmdLine, uriparam); |
|
444 handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine); |
|
445 cmdLine.preventDefault = true; |
|
446 } |
|
447 } |
|
448 catch (e) { |
|
449 Components.utils.reportError(e); |
|
450 } |
|
451 |
|
452 var chromeParam = cmdLine.handleFlagWithParam("chrome", false); |
|
453 if (chromeParam) { |
|
454 |
|
455 // Handle old preference dialog URLs. |
|
456 if (chromeParam == "chrome://browser/content/pref/pref.xul" || |
|
457 (Services.prefs.getBoolPref("browser.preferences.inContent") && |
|
458 chromeParam == "chrome://browser/content/preferences/preferences.xul")) { |
|
459 openPreferences(); |
|
460 cmdLine.preventDefault = true; |
|
461 } else try { |
|
462 // only load URIs which do not inherit chrome privs |
|
463 var features = "chrome,dialog=no,all" + this.getFeatures(cmdLine); |
|
464 var uri = resolveURIInternal(cmdLine, chromeParam); |
|
465 var netutil = Components.classes["@mozilla.org/network/util;1"] |
|
466 .getService(nsINetUtil); |
|
467 if (!netutil.URIChainHasFlags(uri, URI_INHERITS_SECURITY_CONTEXT)) { |
|
468 openWindow(null, uri.spec, "_blank", features); |
|
469 cmdLine.preventDefault = true; |
|
470 } |
|
471 } |
|
472 catch (e) { |
|
473 Components.utils.reportError(e); |
|
474 } |
|
475 } |
|
476 if (cmdLine.handleFlag("preferences", false)) { |
|
477 openPreferences(); |
|
478 cmdLine.preventDefault = true; |
|
479 } |
|
480 if (cmdLine.handleFlag("silent", false)) |
|
481 cmdLine.preventDefault = true; |
|
482 |
|
483 try { |
|
484 var privateWindowParam = cmdLine.handleFlagWithParam("private-window", false); |
|
485 if (privateWindowParam) { |
|
486 var uri = resolveURIInternal(cmdLine, privateWindowParam); |
|
487 handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine, true); |
|
488 cmdLine.preventDefault = true; |
|
489 } |
|
490 } catch (e if e.result == Components.results.NS_ERROR_INVALID_ARG) { |
|
491 // NS_ERROR_INVALID_ARG is thrown when flag exists, but has no param. |
|
492 if (cmdLine.handleFlag("private-window", false)) { |
|
493 openWindow(null, this.chromeURL, "_blank", |
|
494 "chrome,dialog=no,private,all" + this.getFeatures(cmdLine), |
|
495 "about:privatebrowsing"); |
|
496 cmdLine.preventDefault = true; |
|
497 } |
|
498 } |
|
499 |
|
500 var searchParam = cmdLine.handleFlagWithParam("search", false); |
|
501 if (searchParam) { |
|
502 doSearch(searchParam, cmdLine); |
|
503 cmdLine.preventDefault = true; |
|
504 } |
|
505 |
|
506 // The global PB Service consumes this flag, so only eat it in per-window |
|
507 // PB builds. |
|
508 if (cmdLine.handleFlag("private", false)) { |
|
509 PrivateBrowsingUtils.enterTemporaryAutoStartMode(); |
|
510 } |
|
511 |
|
512 var fileParam = cmdLine.handleFlagWithParam("file", false); |
|
513 if (fileParam) { |
|
514 var file = cmdLine.resolveFile(fileParam); |
|
515 var ios = Components.classes["@mozilla.org/network/io-service;1"] |
|
516 .getService(Components.interfaces.nsIIOService); |
|
517 var uri = ios.newFileURI(file); |
|
518 openWindow(null, this.chromeURL, "_blank", |
|
519 "chrome,dialog=no,all" + this.getFeatures(cmdLine), |
|
520 uri.spec); |
|
521 cmdLine.preventDefault = true; |
|
522 } |
|
523 |
|
524 #ifdef XP_WIN |
|
525 // Handle "? searchterm" for Windows Vista start menu integration |
|
526 for (var i = cmdLine.length - 1; i >= 0; --i) { |
|
527 var param = cmdLine.getArgument(i); |
|
528 if (param.match(/^\? /)) { |
|
529 cmdLine.removeArguments(i, i); |
|
530 cmdLine.preventDefault = true; |
|
531 |
|
532 searchParam = param.substr(2); |
|
533 doSearch(searchParam, cmdLine); |
|
534 } |
|
535 } |
|
536 #endif |
|
537 }, |
|
538 |
|
539 helpInfo : " -browser Open a browser window.\n" + |
|
540 " -new-window <url> Open <url> in a new window.\n" + |
|
541 " -new-tab <url> Open <url> in a new tab.\n" + |
|
542 #ifdef XP_WIN |
|
543 " -preferences Open Options dialog.\n" + |
|
544 #else |
|
545 " -preferences Open Preferences dialog.\n" + |
|
546 #endif |
|
547 " -search <term> Search <term> with your default search engine.\n", |
|
548 |
|
549 /* nsIBrowserHandler */ |
|
550 |
|
551 get defaultArgs() { |
|
552 var prefb = Components.classes["@mozilla.org/preferences-service;1"] |
|
553 .getService(nsIPrefBranch); |
|
554 |
|
555 if (!gFirstWindow) { |
|
556 gFirstWindow = true; |
|
557 if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) { |
|
558 return "about:privatebrowsing"; |
|
559 } |
|
560 } |
|
561 |
|
562 var overridePage = ""; |
|
563 var willRestoreSession = false; |
|
564 try { |
|
565 // Read the old value of homepage_override.mstone before |
|
566 // needHomepageOverride updates it, so that we can later add it to the |
|
567 // URL if we do end up showing an overridePage. This makes it possible |
|
568 // to have the overridePage's content vary depending on the version we're |
|
569 // upgrading from. |
|
570 let old_mstone = "unknown"; |
|
571 try { |
|
572 old_mstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone"); |
|
573 } catch (ex) {} |
|
574 let override = needHomepageOverride(prefb); |
|
575 if (override != OVERRIDE_NONE) { |
|
576 switch (override) { |
|
577 case OVERRIDE_NEW_PROFILE: |
|
578 // New profile. |
|
579 overridePage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url"); |
|
580 break; |
|
581 case OVERRIDE_NEW_MSTONE: |
|
582 // Check whether we will restore a session. If we will, we assume |
|
583 // that this is an "update" session. This does not take crashes |
|
584 // into account because that requires waiting for the session file |
|
585 // to be read. If a crash occurs after updating, before restarting, |
|
586 // we may open the startPage in addition to restoring the session. |
|
587 var ss = Components.classes["@mozilla.org/browser/sessionstartup;1"] |
|
588 .getService(Components.interfaces.nsISessionStartup); |
|
589 willRestoreSession = ss.isAutomaticRestoreEnabled(); |
|
590 |
|
591 overridePage = Services.urlFormatter.formatURLPref("startup.homepage_override_url"); |
|
592 if (prefb.prefHasUserValue("app.update.postupdate")) |
|
593 overridePage = getPostUpdateOverridePage(overridePage); |
|
594 |
|
595 overridePage = overridePage.replace("%OLD_VERSION%", old_mstone); |
|
596 break; |
|
597 } |
|
598 } |
|
599 } catch (ex) {} |
|
600 |
|
601 // formatURLPref might return "about:blank" if getting the pref fails |
|
602 if (overridePage == "about:blank") |
|
603 overridePage = ""; |
|
604 |
|
605 var startPage = ""; |
|
606 try { |
|
607 var choice = prefb.getIntPref("browser.startup.page"); |
|
608 if (choice == 1 || choice == 3) |
|
609 startPage = this.startPage; |
|
610 } catch (e) { |
|
611 Components.utils.reportError(e); |
|
612 } |
|
613 |
|
614 if (startPage == "about:blank") |
|
615 startPage = ""; |
|
616 |
|
617 // Only show the startPage if we're not restoring an update session. |
|
618 if (overridePage && startPage && !willRestoreSession) |
|
619 return overridePage + "|" + startPage; |
|
620 |
|
621 return overridePage || startPage || "about:blank"; |
|
622 }, |
|
623 |
|
624 get startPage() { |
|
625 var uri = Services.prefs.getComplexValue("browser.startup.homepage", |
|
626 nsIPrefLocalizedString).data; |
|
627 if (!uri) { |
|
628 Services.prefs.clearUserPref("browser.startup.homepage"); |
|
629 uri = Services.prefs.getComplexValue("browser.startup.homepage", |
|
630 nsIPrefLocalizedString).data; |
|
631 } |
|
632 return uri; |
|
633 }, |
|
634 |
|
635 mFeatures : null, |
|
636 |
|
637 getFeatures : function bch_features(cmdLine) { |
|
638 if (this.mFeatures === null) { |
|
639 this.mFeatures = ""; |
|
640 |
|
641 try { |
|
642 var width = cmdLine.handleFlagWithParam("width", false); |
|
643 var height = cmdLine.handleFlagWithParam("height", false); |
|
644 |
|
645 if (width) |
|
646 this.mFeatures += ",width=" + width; |
|
647 if (height) |
|
648 this.mFeatures += ",height=" + height; |
|
649 } |
|
650 catch (e) { |
|
651 } |
|
652 |
|
653 // The global PB Service consumes this flag, so only eat it in per-window |
|
654 // PB builds. |
|
655 if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) { |
|
656 this.mFeatures = ",private"; |
|
657 } |
|
658 } |
|
659 |
|
660 return this.mFeatures; |
|
661 }, |
|
662 |
|
663 /* nsIContentHandler */ |
|
664 |
|
665 handleContent : function bch_handleContent(contentType, context, request) { |
|
666 try { |
|
667 var webNavInfo = Components.classes["@mozilla.org/webnavigation-info;1"] |
|
668 .getService(nsIWebNavigationInfo); |
|
669 if (!webNavInfo.isTypeSupported(contentType, null)) { |
|
670 throw NS_ERROR_WONT_HANDLE_CONTENT; |
|
671 } |
|
672 } catch (e) { |
|
673 throw NS_ERROR_WONT_HANDLE_CONTENT; |
|
674 } |
|
675 |
|
676 request.QueryInterface(nsIChannel); |
|
677 handURIToExistingBrowser(request.URI, |
|
678 nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, null); |
|
679 request.cancel(NS_BINDING_ABORTED); |
|
680 }, |
|
681 |
|
682 /* nsICommandLineValidator */ |
|
683 validate : function bch_validate(cmdLine) { |
|
684 // Other handlers may use osint so only handle the osint flag if the url |
|
685 // flag is also present and the command line is valid. |
|
686 var osintFlagIdx = cmdLine.findFlag("osint", false); |
|
687 var urlFlagIdx = cmdLine.findFlag("url", false); |
|
688 if (urlFlagIdx > -1 && (osintFlagIdx > -1 || |
|
689 cmdLine.state == nsICommandLine.STATE_REMOTE_EXPLICIT)) { |
|
690 var urlParam = cmdLine.getArgument(urlFlagIdx + 1); |
|
691 if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/.test(urlParam)) |
|
692 throw NS_ERROR_ABORT; |
|
693 cmdLine.handleFlag("osint", false) |
|
694 } |
|
695 }, |
|
696 }; |
|
697 var gBrowserContentHandler = new nsBrowserContentHandler(); |
|
698 |
|
699 function handURIToExistingBrowser(uri, location, cmdLine, forcePrivate) |
|
700 { |
|
701 if (!shouldLoadURI(uri)) |
|
702 return; |
|
703 |
|
704 // Unless using a private window is forced, open external links in private |
|
705 // windows only if we're in perma-private mode. |
|
706 var allowPrivate = forcePrivate || PrivateBrowsingUtils.permanentPrivateBrowsing; |
|
707 var navWin = RecentWindow.getMostRecentBrowserWindow({private: allowPrivate}); |
|
708 if (!navWin) { |
|
709 // if we couldn't load it in an existing window, open a new one |
|
710 var features = "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine); |
|
711 if (forcePrivate) { |
|
712 features += ",private"; |
|
713 } |
|
714 openWindow(null, gBrowserContentHandler.chromeURL, "_blank", features, uri.spec); |
|
715 return; |
|
716 } |
|
717 |
|
718 var navNav = navWin.QueryInterface(nsIInterfaceRequestor) |
|
719 .getInterface(nsIWebNavigation); |
|
720 var rootItem = navNav.QueryInterface(nsIDocShellTreeItem).rootTreeItem; |
|
721 var rootWin = rootItem.QueryInterface(nsIInterfaceRequestor) |
|
722 .getInterface(nsIDOMWindow); |
|
723 var bwin = rootWin.QueryInterface(nsIDOMChromeWindow).browserDOMWindow; |
|
724 bwin.openURI(uri, null, location, |
|
725 nsIBrowserDOMWindow.OPEN_EXTERNAL); |
|
726 } |
|
727 |
|
728 function nsDefaultCommandLineHandler() { |
|
729 } |
|
730 |
|
731 nsDefaultCommandLineHandler.prototype = { |
|
732 classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"), |
|
733 |
|
734 /* nsISupports */ |
|
735 QueryInterface : function dch_QI(iid) { |
|
736 if (!iid.equals(nsISupports) && |
|
737 !iid.equals(nsICommandLineHandler)) |
|
738 throw Components.results.NS_ERROR_NO_INTERFACE; |
|
739 |
|
740 return this; |
|
741 }, |
|
742 |
|
743 #ifdef XP_WIN |
|
744 _haveProfile: false, |
|
745 #endif |
|
746 |
|
747 /* nsICommandLineHandler */ |
|
748 handle : function dch_handle(cmdLine) { |
|
749 var urilist = []; |
|
750 |
|
751 #ifdef XP_WIN |
|
752 // If we don't have a profile selected yet (e.g. the Profile Manager is |
|
753 // displayed) we will crash if we open an url and then select a profile. To |
|
754 // prevent this handle all url command line flags and set the command line's |
|
755 // preventDefault to true to prevent the display of the ui. The initial |
|
756 // command line will be retained when nsAppRunner calls LaunchChild though |
|
757 // urls launched after the initial launch will be lost. |
|
758 if (!this._haveProfile) { |
|
759 try { |
|
760 // This will throw when a profile has not been selected. |
|
761 var fl = Components.classes["@mozilla.org/file/directory_service;1"] |
|
762 .getService(Components.interfaces.nsIProperties); |
|
763 var dir = fl.get("ProfD", Components.interfaces.nsILocalFile); |
|
764 this._haveProfile = true; |
|
765 } |
|
766 catch (e) { |
|
767 while ((ar = cmdLine.handleFlagWithParam("url", false))) { } |
|
768 cmdLine.preventDefault = true; |
|
769 } |
|
770 } |
|
771 #endif |
|
772 |
|
773 try { |
|
774 var ar; |
|
775 while ((ar = cmdLine.handleFlagWithParam("url", false))) { |
|
776 var uri = resolveURIInternal(cmdLine, ar); |
|
777 urilist.push(uri); |
|
778 } |
|
779 } |
|
780 catch (e) { |
|
781 Components.utils.reportError(e); |
|
782 } |
|
783 |
|
784 count = cmdLine.length; |
|
785 |
|
786 for (i = 0; i < count; ++i) { |
|
787 var curarg = cmdLine.getArgument(i); |
|
788 if (curarg.match(/^-/)) { |
|
789 Components.utils.reportError("Warning: unrecognized command line flag " + curarg + "\n"); |
|
790 // To emulate the pre-nsICommandLine behavior, we ignore |
|
791 // the argument after an unrecognized flag. |
|
792 ++i; |
|
793 } else { |
|
794 try { |
|
795 urilist.push(resolveURIInternal(cmdLine, curarg)); |
|
796 } |
|
797 catch (e) { |
|
798 Components.utils.reportError("Error opening URI '" + curarg + "' from the command line: " + e + "\n"); |
|
799 } |
|
800 } |
|
801 } |
|
802 |
|
803 if (urilist.length) { |
|
804 if (cmdLine.state != nsICommandLine.STATE_INITIAL_LAUNCH && |
|
805 urilist.length == 1) { |
|
806 // Try to find an existing window and load our URI into the |
|
807 // current tab, new tab, or new window as prefs determine. |
|
808 try { |
|
809 handURIToExistingBrowser(urilist[0], nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, cmdLine); |
|
810 return; |
|
811 } |
|
812 catch (e) { |
|
813 } |
|
814 } |
|
815 |
|
816 var URLlist = urilist.filter(shouldLoadURI).map(function (u) u.spec); |
|
817 if (URLlist.length) { |
|
818 openWindow(null, gBrowserContentHandler.chromeURL, "_blank", |
|
819 "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine), |
|
820 URLlist); |
|
821 } |
|
822 |
|
823 } |
|
824 else if (!cmdLine.preventDefault) { |
|
825 // Passing defaultArgs, so use NO_EXTERNAL_URIS |
|
826 openWindow(null, gBrowserContentHandler.chromeURL, "_blank", |
|
827 "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine), |
|
828 gBrowserContentHandler.defaultArgs, NO_EXTERNAL_URIS); |
|
829 } |
|
830 }, |
|
831 |
|
832 helpInfo : "", |
|
833 }; |
|
834 |
|
835 var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler]; |
|
836 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); |