|
1 /* -*- Mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil; -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 const Cc = Components.classes; |
|
7 const Ci = Components.interfaces; |
|
8 const Cu = Components.utils; |
|
9 const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService; |
|
10 |
|
11 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
12 Cu.import("resource://gre/modules/Services.jsm"); |
|
13 |
|
14 function openWindow(aParent, aURL, aTarget, aFeatures, aArgs) { |
|
15 let argString = null; |
|
16 if (aArgs && !(aArgs instanceof Ci.nsISupportsArray)) { |
|
17 argString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); |
|
18 argString.data = aArgs; |
|
19 } |
|
20 |
|
21 return Services.ww.openWindow(aParent, aURL, aTarget, aFeatures, argString || aArgs); |
|
22 } |
|
23 |
|
24 function resolveURIInternal(aCmdLine, aArgument) { |
|
25 let uri = aCmdLine.resolveURI(aArgument); |
|
26 |
|
27 if (!(uri instanceof Ci.nsIFileURL)) |
|
28 return uri; |
|
29 |
|
30 try { |
|
31 if (uri.file.exists()) |
|
32 return uri; |
|
33 } catch (e) { |
|
34 Cu.reportError(e); |
|
35 } |
|
36 |
|
37 try { |
|
38 let urifixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup); |
|
39 uri = urifixup.createFixupURI(aArgument, 0); |
|
40 } catch (e) { |
|
41 Cu.reportError(e); |
|
42 } |
|
43 |
|
44 return uri; |
|
45 } |
|
46 |
|
47 /** |
|
48 * Determines whether a home page override is needed. |
|
49 * Returns: |
|
50 * "new profile" if this is the first run with a new profile. |
|
51 * "new version" if this is the first run with a build with a different |
|
52 * Gecko milestone (i.e. right after an upgrade). |
|
53 * "none" otherwise. |
|
54 */ |
|
55 function needHomepageOverride() { |
|
56 let savedmstone = null; |
|
57 try { |
|
58 savedmstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone"); |
|
59 } catch (e) {} |
|
60 |
|
61 if (savedmstone == "ignore") |
|
62 return "none"; |
|
63 |
|
64 let ourmstone = Services.appinfo.platformVersion; |
|
65 |
|
66 if (ourmstone != savedmstone) { |
|
67 Services.prefs.setCharPref("browser.startup.homepage_override.mstone", ourmstone); |
|
68 |
|
69 return (savedmstone ? "new version" : "new profile"); |
|
70 } |
|
71 |
|
72 return "none"; |
|
73 } |
|
74 |
|
75 function getHomePage() { |
|
76 let url = "about:newtab"; |
|
77 try { |
|
78 url = Services.prefs.getComplexValue("browser.startup.homepage", Ci.nsIPrefLocalizedString).data; |
|
79 } catch (e) { } |
|
80 |
|
81 return url; |
|
82 } |
|
83 |
|
84 function showPanelWhenReady(aWindow, aPage) { |
|
85 aWindow.addEventListener("UIReadyDelayed", function(aEvent) { |
|
86 aWindow.PanelUI.show(aPage); |
|
87 }, false); |
|
88 } |
|
89 |
|
90 function haveSystemLocale() { |
|
91 let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService); |
|
92 let systemLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE"); |
|
93 return isLocaleAvailable(systemLocale); |
|
94 } |
|
95 |
|
96 function checkCurrentLocale() { |
|
97 if (Services.prefs.prefHasUserValue("general.useragent.locale")) { |
|
98 // if the user has a compatible locale from a different buildid, we need to update |
|
99 var buildID = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).platformBuildID; |
|
100 let localeBuildID = Services.prefs.getCharPref("extensions.compatability.locales.buildid"); |
|
101 if (buildID != localeBuildID) |
|
102 return false; |
|
103 |
|
104 let currentLocale = Services.prefs.getCharPref("general.useragent.locale"); |
|
105 return isLocaleAvailable(currentLocale); |
|
106 } |
|
107 return true; |
|
108 } |
|
109 |
|
110 function isLocaleAvailable(aLocale) { |
|
111 let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); |
|
112 chrome.QueryInterface(Ci.nsIToolkitChromeRegistry); |
|
113 let availableLocales = chrome.getLocalesForPackage("browser"); |
|
114 |
|
115 let locale = aLocale.split("-")[0]; |
|
116 let localeRegEx = new RegExp("^" + locale); |
|
117 |
|
118 while (availableLocales.hasMore()) { |
|
119 let locale = availableLocales.getNext(); |
|
120 if (localeRegEx.test(locale)) |
|
121 return true; |
|
122 } |
|
123 return false; |
|
124 } |
|
125 |
|
126 function BrowserCLH() { } |
|
127 |
|
128 BrowserCLH.prototype = { |
|
129 // |
|
130 // nsICommandLineHandler |
|
131 // |
|
132 handle: function fs_handle(aCmdLine) { |
|
133 #ifdef DEBUG |
|
134 for (var idx = 0; idx < aCmdLine.length; idx++) { |
|
135 dump(aCmdLine.getArgument(idx) + "\n"); |
|
136 } |
|
137 #endif |
|
138 // Instantiate the search service so the search engine cache is created now |
|
139 // instead when the application is running. The install process will register |
|
140 // this component by using the -silent command line flag, thereby creating |
|
141 // the cache during install, not runtime. |
|
142 // NOTE: This code assumes this CLH is run before the nsDefaultCLH, which |
|
143 // consumes the "-silent" flag. |
|
144 if (aCmdLine.findFlag("silent", false) > -1) { |
|
145 let searchService = Services.search; |
|
146 let autoComplete = Cc["@mozilla.org/autocomplete/search;1?name=history"]. |
|
147 getService(Ci.nsIAutoCompleteSearch); |
|
148 return; |
|
149 } |
|
150 |
|
151 // Handle chrome windows loaded via commandline |
|
152 let chromeParam = aCmdLine.handleFlagWithParam("chrome", false); |
|
153 if (chromeParam) { |
|
154 try { |
|
155 // Only load URIs which do not inherit chrome privs |
|
156 let features = "chrome,dialog=no,all"; |
|
157 let uri = resolveURIInternal(aCmdLine, chromeParam); |
|
158 let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil); |
|
159 if (!netutil.URIChainHasFlags(uri, Ci.nsIHttpProtocolHandler.URI_INHERITS_SECURITY_CONTEXT)) { |
|
160 openWindow(null, uri.spec, "_blank", features, null); |
|
161 |
|
162 // Stop the normal commandline processing from continuing |
|
163 aCmdLine.preventDefault = true; |
|
164 } |
|
165 } catch (e) { |
|
166 Cu.reportError(e); |
|
167 } |
|
168 return; |
|
169 } |
|
170 |
|
171 // Check and remove the alert flag here, but we'll handle it a bit later - see below |
|
172 let alertFlag = aCmdLine.handleFlagWithParam("alert", false); |
|
173 |
|
174 // Check and remove the webapp param |
|
175 let appFlag = aCmdLine.handleFlagWithParam("webapp", false); |
|
176 let appURI; |
|
177 if (appFlag) |
|
178 appURI = resolveURIInternal(aCmdLine, appFlag); |
|
179 |
|
180 // Keep an array of possible URL arguments |
|
181 let uris = []; |
|
182 |
|
183 // Check for the "url" flag |
|
184 let uriFlag = aCmdLine.handleFlagWithParam("url", false); |
|
185 if (uriFlag) { |
|
186 let uri = resolveURIInternal(aCmdLine, uriFlag); |
|
187 if (uri) |
|
188 uris.push(uri); |
|
189 } |
|
190 |
|
191 // Check for the "search" flag |
|
192 let searchParam = aCmdLine.handleFlagWithParam("search", false); |
|
193 if (searchParam) { |
|
194 var ss = Components.classes["@mozilla.org/browser/search-service;1"] |
|
195 .getService(nsIBrowserSearchService); |
|
196 var submission = ss.defaultEngine.getSubmission(searchParam.replace("\"", "", "g")); |
|
197 uris.push(submission.uri); |
|
198 } |
|
199 |
|
200 for (let i = 0; i < aCmdLine.length; i++) { |
|
201 let arg = aCmdLine.getArgument(i); |
|
202 if (!arg || arg[0] == '-') |
|
203 continue; |
|
204 |
|
205 let uri = resolveURIInternal(aCmdLine, arg); |
|
206 if (uri) |
|
207 uris.push(uri); |
|
208 } |
|
209 |
|
210 // Open the main browser window, if we don't already have one |
|
211 let browserWin; |
|
212 try { |
|
213 let localeWin = Services.wm.getMostRecentWindow("navigator:localepicker"); |
|
214 if (localeWin) { |
|
215 localeWin.focus(); |
|
216 aCmdLine.preventDefault = true; |
|
217 return; |
|
218 } |
|
219 |
|
220 browserWin = Services.wm.getMostRecentWindow("navigator:browser"); |
|
221 if (!browserWin) { |
|
222 // Default to the saved homepage |
|
223 let defaultURL = getHomePage(); |
|
224 |
|
225 // Override the default if we have a URL passed on command line |
|
226 if (uris.length > 0) { |
|
227 defaultURL = uris[0].spec; |
|
228 uris = uris.slice(1); |
|
229 } |
|
230 |
|
231 // Show the locale selector if we have a new profile, or if the selected locale is no longer compatible |
|
232 let showLocalePicker = Services.prefs.getBoolPref("browser.firstrun.show.localepicker"); |
|
233 if ((needHomepageOverride() == "new profile" && showLocalePicker && !haveSystemLocale())) { // || !checkCurrentLocale()) { |
|
234 browserWin = openWindow(null, "chrome://browser/content/localePicker.xul", "_blank", "chrome,dialog=no,all", defaultURL); |
|
235 aCmdLine.preventDefault = true; |
|
236 return; |
|
237 } |
|
238 |
|
239 browserWin = openWindow(null, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", defaultURL); |
|
240 } |
|
241 |
|
242 browserWin.focus(); |
|
243 |
|
244 // Stop the normal commandline processing from continuing. We just opened the main browser window |
|
245 aCmdLine.preventDefault = true; |
|
246 } catch (e) { |
|
247 Cu.reportError(e); |
|
248 } |
|
249 |
|
250 // Assumption: All remaining command line arguments have been sent remotely (browser is already running) |
|
251 // Action: Open any URLs we find into an existing browser window |
|
252 |
|
253 // First, get a browserDOMWindow object |
|
254 while (!browserWin.browserDOMWindow) |
|
255 Services.tm.currentThread.processNextEvent(true); |
|
256 |
|
257 // Open any URIs into new tabs |
|
258 for (let i = 0; i < uris.length; i++) |
|
259 browserWin.browserDOMWindow.openURI(uris[i], null, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB, Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL); |
|
260 |
|
261 if (appURI) |
|
262 browserWin.browserDOMWindow.openURI(appURI, null, browserWin.OPEN_APPTAB, Ci.nsIBrowserDOMWindow.OPEN_NEW); |
|
263 |
|
264 // Handle the notification, if called from it |
|
265 if (alertFlag) { |
|
266 if (alertFlag == "update-app") { |
|
267 // Notification was already displayed and clicked, skip it next time |
|
268 Services.prefs.setBoolPref("app.update.skipNotification", true); |
|
269 |
|
270 var updateService = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService); |
|
271 var updateTimerCallback = updateService.QueryInterface(Ci.nsITimerCallback); |
|
272 updateTimerCallback.notify(null); |
|
273 } |
|
274 } |
|
275 }, |
|
276 |
|
277 // QI |
|
278 QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), |
|
279 |
|
280 // XPCOMUtils factory |
|
281 classID: Components.ID("{be623d20-d305-11de-8a39-0800200c9a66}"), |
|
282 }; |
|
283 |
|
284 var components = [ BrowserCLH ]; |
|
285 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); |