Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 : #include "mozilla/ArrayUtils.h"
7 :
8 : #include "nsCOMPtr.h"
9 : #include "nsGNOMEShellService.h"
10 : #include "nsShellService.h"
11 : #include "nsIServiceManager.h"
12 : #include "nsIFile.h"
13 : #include "nsIProperties.h"
14 : #include "nsDirectoryServiceDefs.h"
15 : #include "nsIPrefService.h"
16 : #include "prenv.h"
17 : #include "nsString.h"
18 : #include "nsIGConfService.h"
19 : #include "nsIGIOService.h"
20 : #include "nsIGSettingsService.h"
21 : #include "nsIStringBundle.h"
22 : #include "nsIOutputStream.h"
23 : #include "nsIProcess.h"
24 : #include "nsServiceManagerUtils.h"
25 : #include "nsComponentManagerUtils.h"
26 : #include "nsIDOMHTMLImageElement.h"
27 : #include "nsIImageLoadingContent.h"
28 : #include "imgIRequest.h"
29 : #include "imgIContainer.h"
30 : #include "mozilla/Sprintf.h"
31 : #if defined(MOZ_WIDGET_GTK)
32 : #include "nsIImageToPixbuf.h"
33 : #endif
34 : #include "nsXULAppAPI.h"
35 : #include "gfxPlatform.h"
36 :
37 : #include <glib.h>
38 : #include <glib-object.h>
39 : #include <gtk/gtk.h>
40 : #include <gdk/gdk.h>
41 : #include <gdk-pixbuf/gdk-pixbuf.h>
42 : #include <limits.h>
43 : #include <stdlib.h>
44 :
45 : using namespace mozilla;
46 :
47 : struct ProtocolAssociation
48 : {
49 : const char *name;
50 : bool essential;
51 : };
52 :
53 : struct MimeTypeAssociation
54 : {
55 : const char *mimeType;
56 : const char *extensions;
57 : };
58 :
59 : static const ProtocolAssociation appProtocols[] = {
60 : { "http", true },
61 : { "https", true },
62 : { "ftp", false },
63 : { "chrome", false }
64 : };
65 :
66 : static const MimeTypeAssociation appTypes[] = {
67 : { "text/html", "htm html shtml" },
68 : { "application/xhtml+xml", "xhtml xht" }
69 : };
70 :
71 : // GConf registry key constants
72 : #define DG_BACKGROUND "/desktop/gnome/background"
73 :
74 : #define kDesktopImageKey DG_BACKGROUND "/picture_filename"
75 : #define kDesktopOptionsKey DG_BACKGROUND "/picture_options"
76 : #define kDesktopDrawBGKey DG_BACKGROUND "/draw_background"
77 : #define kDesktopColorKey DG_BACKGROUND "/primary_color"
78 :
79 : #define kDesktopBGSchema "org.gnome.desktop.background"
80 : #define kDesktopImageGSKey "picture-uri"
81 : #define kDesktopOptionGSKey "picture-options"
82 : #define kDesktopDrawBGGSKey "draw-background"
83 : #define kDesktopColorGSKey "primary-color"
84 :
85 : nsresult
86 0 : nsGNOMEShellService::Init()
87 : {
88 : nsresult rv;
89 :
90 0 : if (gfxPlatform::IsHeadless()) {
91 0 : return NS_ERROR_NOT_AVAILABLE;
92 : }
93 :
94 : // GConf, GSettings or GIO _must_ be available, or we do not allow
95 : // CreateInstance to succeed.
96 :
97 0 : nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
98 : nsCOMPtr<nsIGIOService> giovfs =
99 0 : do_GetService(NS_GIOSERVICE_CONTRACTID);
100 : nsCOMPtr<nsIGSettingsService> gsettings =
101 0 : do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
102 :
103 0 : if (!gconf && !giovfs && !gsettings)
104 0 : return NS_ERROR_NOT_AVAILABLE;
105 :
106 : // Check G_BROKEN_FILENAMES. If it's set, then filenames in glib use
107 : // the locale encoding. If it's not set, they use UTF-8.
108 0 : mUseLocaleFilenames = PR_GetEnv("G_BROKEN_FILENAMES") != nullptr;
109 :
110 0 : if (GetAppPathFromLauncher())
111 0 : return NS_OK;
112 :
113 : nsCOMPtr<nsIProperties> dirSvc
114 0 : (do_GetService("@mozilla.org/file/directory_service;1"));
115 0 : NS_ENSURE_TRUE(dirSvc, NS_ERROR_NOT_AVAILABLE);
116 :
117 0 : nsCOMPtr<nsIFile> appPath;
118 0 : rv = dirSvc->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
119 0 : getter_AddRefs(appPath));
120 0 : NS_ENSURE_SUCCESS(rv, rv);
121 :
122 0 : return appPath->GetNativePath(mAppPath);
123 : }
124 :
125 0 : NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIGNOMEShellService, nsIShellService)
126 :
127 : bool
128 0 : nsGNOMEShellService::GetAppPathFromLauncher()
129 : {
130 : gchar *tmp;
131 :
132 0 : const char *launcher = PR_GetEnv("MOZ_APP_LAUNCHER");
133 0 : if (!launcher)
134 0 : return false;
135 :
136 0 : if (g_path_is_absolute(launcher)) {
137 0 : mAppPath = launcher;
138 0 : tmp = g_path_get_basename(launcher);
139 0 : gchar *fullpath = g_find_program_in_path(tmp);
140 0 : if (fullpath && mAppPath.Equals(fullpath))
141 0 : mAppIsInPath = true;
142 0 : g_free(fullpath);
143 : } else {
144 0 : tmp = g_find_program_in_path(launcher);
145 0 : if (!tmp)
146 0 : return false;
147 0 : mAppPath = tmp;
148 0 : mAppIsInPath = true;
149 : }
150 :
151 0 : g_free(tmp);
152 0 : return true;
153 : }
154 :
155 : bool
156 0 : nsGNOMEShellService::KeyMatchesAppName(const char *aKeyValue) const
157 : {
158 :
159 : gchar *commandPath;
160 0 : if (mUseLocaleFilenames) {
161 : gchar *nativePath = g_filename_from_utf8(aKeyValue, -1,
162 0 : nullptr, nullptr, nullptr);
163 0 : if (!nativePath) {
164 0 : NS_ERROR("Error converting path to filesystem encoding");
165 0 : return false;
166 : }
167 :
168 0 : commandPath = g_find_program_in_path(nativePath);
169 0 : g_free(nativePath);
170 : } else {
171 0 : commandPath = g_find_program_in_path(aKeyValue);
172 : }
173 :
174 0 : if (!commandPath)
175 0 : return false;
176 :
177 0 : bool matches = mAppPath.Equals(commandPath);
178 0 : g_free(commandPath);
179 0 : return matches;
180 : }
181 :
182 : bool
183 0 : nsGNOMEShellService::CheckHandlerMatchesAppName(const nsACString &handler) const
184 : {
185 : gint argc;
186 : gchar **argv;
187 0 : nsAutoCString command(handler);
188 :
189 : // The string will be something of the form: [/path/to/]browser "%s"
190 : // We want to remove all of the parameters and get just the binary name.
191 :
192 0 : if (g_shell_parse_argv(command.get(), &argc, &argv, nullptr) && argc > 0) {
193 0 : command.Assign(argv[0]);
194 0 : g_strfreev(argv);
195 : }
196 :
197 0 : if (!KeyMatchesAppName(command.get()))
198 0 : return false; // the handler is set to another app
199 :
200 0 : return true;
201 : }
202 :
203 : NS_IMETHODIMP
204 0 : nsGNOMEShellService::IsDefaultBrowser(bool aStartupCheck,
205 : bool aForAllTypes,
206 : bool* aIsDefaultBrowser)
207 : {
208 0 : *aIsDefaultBrowser = false;
209 :
210 0 : nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
211 0 : nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
212 :
213 : bool enabled;
214 0 : nsAutoCString handler;
215 0 : nsCOMPtr<nsIGIOMimeApp> gioApp;
216 :
217 0 : for (unsigned int i = 0; i < ArrayLength(appProtocols); ++i) {
218 0 : if (!appProtocols[i].essential)
219 0 : continue;
220 :
221 0 : if (gconf) {
222 0 : handler.Truncate();
223 0 : gconf->GetAppForProtocol(nsDependentCString(appProtocols[i].name),
224 0 : &enabled, handler);
225 :
226 0 : if (!CheckHandlerMatchesAppName(handler) || !enabled)
227 0 : return NS_OK; // the handler is disabled or set to another app
228 : }
229 :
230 0 : if (giovfs) {
231 0 : handler.Truncate();
232 0 : giovfs->GetAppForURIScheme(nsDependentCString(appProtocols[i].name),
233 0 : getter_AddRefs(gioApp));
234 0 : if (!gioApp)
235 0 : return NS_OK;
236 :
237 0 : gioApp->GetCommand(handler);
238 :
239 0 : if (!CheckHandlerMatchesAppName(handler))
240 0 : return NS_OK; // the handler is set to another app
241 : }
242 : }
243 :
244 0 : *aIsDefaultBrowser = true;
245 :
246 0 : return NS_OK;
247 : }
248 :
249 : NS_IMETHODIMP
250 0 : nsGNOMEShellService::SetDefaultBrowser(bool aClaimAllTypes,
251 : bool aForAllUsers)
252 : {
253 : #ifdef DEBUG
254 0 : if (aForAllUsers)
255 0 : NS_WARNING("Setting the default browser for all users is not yet supported");
256 : #endif
257 :
258 0 : nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
259 0 : nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
260 0 : if (gconf) {
261 0 : nsAutoCString appKeyValue;
262 0 : if (mAppIsInPath) {
263 : // mAppPath is in the users path, so use only the basename as the launcher
264 0 : gchar *tmp = g_path_get_basename(mAppPath.get());
265 0 : appKeyValue = tmp;
266 0 : g_free(tmp);
267 : } else {
268 0 : appKeyValue = mAppPath;
269 : }
270 :
271 0 : appKeyValue.AppendLiteral(" %s");
272 :
273 0 : for (unsigned int i = 0; i < ArrayLength(appProtocols); ++i) {
274 0 : if (appProtocols[i].essential || aClaimAllTypes) {
275 0 : gconf->SetAppForProtocol(nsDependentCString(appProtocols[i].name),
276 0 : appKeyValue);
277 : }
278 : }
279 : }
280 :
281 0 : if (giovfs) {
282 : nsresult rv;
283 : nsCOMPtr<nsIStringBundleService> bundleService =
284 0 : do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
285 0 : NS_ENSURE_SUCCESS(rv, rv);
286 :
287 0 : nsCOMPtr<nsIStringBundle> brandBundle;
288 0 : rv = bundleService->CreateBundle(BRAND_PROPERTIES, getter_AddRefs(brandBundle));
289 0 : NS_ENSURE_SUCCESS(rv, rv);
290 :
291 0 : nsString brandShortName;
292 0 : brandBundle->GetStringFromName(u"brandShortName",
293 0 : getter_Copies(brandShortName));
294 :
295 : // use brandShortName as the application id.
296 0 : NS_ConvertUTF16toUTF8 id(brandShortName);
297 0 : nsCOMPtr<nsIGIOMimeApp> appInfo;
298 0 : rv = giovfs->CreateAppFromCommand(mAppPath,
299 : id,
300 0 : getter_AddRefs(appInfo));
301 0 : NS_ENSURE_SUCCESS(rv, rv);
302 :
303 : // set handler for the protocols
304 0 : for (unsigned int i = 0; i < ArrayLength(appProtocols); ++i) {
305 0 : if (appProtocols[i].essential || aClaimAllTypes) {
306 0 : appInfo->SetAsDefaultForURIScheme(nsDependentCString(appProtocols[i].name));
307 : }
308 : }
309 :
310 : // set handler for .html and xhtml files and MIME types:
311 0 : if (aClaimAllTypes) {
312 : // Add mime types for html, xhtml extension and set app to just created appinfo.
313 0 : for (unsigned int i = 0; i < ArrayLength(appTypes); ++i) {
314 0 : appInfo->SetAsDefaultForMimeType(nsDependentCString(appTypes[i].mimeType));
315 0 : appInfo->SetAsDefaultForFileExtensions(nsDependentCString(appTypes[i].extensions));
316 : }
317 : }
318 : }
319 :
320 0 : nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
321 0 : if (prefs) {
322 0 : (void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
323 : // Reset the number of times the dialog should be shown
324 : // before it is silenced.
325 0 : (void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
326 : }
327 :
328 0 : return NS_OK;
329 : }
330 :
331 : NS_IMETHODIMP
332 0 : nsGNOMEShellService::GetCanSetDesktopBackground(bool* aResult)
333 : {
334 : // setting desktop background is currently only supported
335 : // for Gnome or desktops using the same GSettings and GConf keys
336 0 : const char* gnomeSession = getenv("GNOME_DESKTOP_SESSION_ID");
337 0 : if (gnomeSession) {
338 0 : *aResult = true;
339 : } else {
340 0 : *aResult = false;
341 : }
342 :
343 0 : return NS_OK;
344 : }
345 :
346 : static nsresult
347 0 : WriteImage(const nsCString& aPath, imgIContainer* aImage)
348 : {
349 : #if !defined(MOZ_WIDGET_GTK)
350 : return NS_ERROR_NOT_AVAILABLE;
351 : #else
352 : nsCOMPtr<nsIImageToPixbuf> imgToPixbuf =
353 0 : do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1");
354 0 : if (!imgToPixbuf)
355 0 : return NS_ERROR_NOT_AVAILABLE;
356 :
357 0 : GdkPixbuf* pixbuf = imgToPixbuf->ConvertImageToPixbuf(aImage);
358 0 : if (!pixbuf)
359 0 : return NS_ERROR_NOT_AVAILABLE;
360 :
361 0 : gboolean res = gdk_pixbuf_save(pixbuf, aPath.get(), "png", nullptr, nullptr);
362 :
363 0 : g_object_unref(pixbuf);
364 0 : return res ? NS_OK : NS_ERROR_FAILURE;
365 : #endif
366 : }
367 :
368 : NS_IMETHODIMP
369 0 : nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement,
370 : int32_t aPosition)
371 : {
372 : nsresult rv;
373 0 : nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement, &rv);
374 0 : if (!imageContent) return rv;
375 :
376 : // get the image container
377 0 : nsCOMPtr<imgIRequest> request;
378 0 : rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
379 0 : getter_AddRefs(request));
380 0 : if (!request) return rv;
381 0 : nsCOMPtr<imgIContainer> container;
382 0 : rv = request->GetImage(getter_AddRefs(container));
383 0 : if (!container) return rv;
384 :
385 : // Set desktop wallpaper filling style
386 0 : nsAutoCString options;
387 0 : if (aPosition == BACKGROUND_TILE)
388 0 : options.AssignLiteral("wallpaper");
389 0 : else if (aPosition == BACKGROUND_STRETCH)
390 0 : options.AssignLiteral("stretched");
391 0 : else if (aPosition == BACKGROUND_FILL)
392 0 : options.AssignLiteral("zoom");
393 0 : else if (aPosition == BACKGROUND_FIT)
394 0 : options.AssignLiteral("scaled");
395 : else
396 0 : options.AssignLiteral("centered");
397 :
398 : // Write the background file to the home directory.
399 0 : nsAutoCString filePath(PR_GetEnv("HOME"));
400 :
401 : // get the product brand name from localized strings
402 0 : nsString brandName;
403 0 : nsCID bundleCID = NS_STRINGBUNDLESERVICE_CID;
404 0 : nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(bundleCID));
405 0 : if (bundleService) {
406 0 : nsCOMPtr<nsIStringBundle> brandBundle;
407 0 : rv = bundleService->CreateBundle(BRAND_PROPERTIES,
408 0 : getter_AddRefs(brandBundle));
409 0 : if (NS_SUCCEEDED(rv) && brandBundle) {
410 0 : rv = brandBundle->GetStringFromName(u"brandShortName",
411 0 : getter_Copies(brandName));
412 0 : NS_ENSURE_SUCCESS(rv, rv);
413 : }
414 : }
415 :
416 : // build the file name
417 0 : filePath.Append('/');
418 0 : filePath.Append(NS_ConvertUTF16toUTF8(brandName));
419 0 : filePath.AppendLiteral("_wallpaper.png");
420 :
421 : // write the image to a file in the home dir
422 0 : rv = WriteImage(filePath, container);
423 0 : NS_ENSURE_SUCCESS(rv, rv);
424 :
425 : // Try GSettings first. If we don't have GSettings or the right schema, fall back
426 : // to using GConf instead. Note that if GSettings works ok, the changes get
427 : // mirrored to GConf by the gsettings->gconf bridge in gnome-settings-daemon
428 : nsCOMPtr<nsIGSettingsService> gsettings =
429 0 : do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
430 0 : if (gsettings) {
431 0 : nsCOMPtr<nsIGSettingsCollection> background_settings;
432 0 : gsettings->GetCollectionForSchema(
433 0 : NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings));
434 0 : if (background_settings) {
435 0 : gchar *file_uri = g_filename_to_uri(filePath.get(), nullptr, nullptr);
436 0 : if (!file_uri)
437 0 : return NS_ERROR_FAILURE;
438 :
439 0 : background_settings->SetString(NS_LITERAL_CSTRING(kDesktopOptionGSKey),
440 0 : options);
441 :
442 0 : background_settings->SetString(NS_LITERAL_CSTRING(kDesktopImageGSKey),
443 0 : nsDependentCString(file_uri));
444 0 : g_free(file_uri);
445 0 : background_settings->SetBoolean(NS_LITERAL_CSTRING(kDesktopDrawBGGSKey),
446 0 : true);
447 0 : return rv;
448 : }
449 : }
450 :
451 : // if the file was written successfully, set it as the system wallpaper
452 0 : nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
453 :
454 0 : if (gconf) {
455 0 : gconf->SetString(NS_LITERAL_CSTRING(kDesktopOptionsKey), options);
456 :
457 : // Set the image to an empty string first to force a refresh
458 : // (since we could be writing a new image on top of an existing
459 : // Firefox_wallpaper.png and nautilus doesn't monitor the file for changes)
460 0 : gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey),
461 0 : EmptyCString());
462 :
463 0 : gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), filePath);
464 0 : gconf->SetBool(NS_LITERAL_CSTRING(kDesktopDrawBGKey), true);
465 : }
466 :
467 0 : return rv;
468 : }
469 :
470 : #define COLOR_16_TO_8_BIT(_c) ((_c) >> 8)
471 : #define COLOR_8_TO_16_BIT(_c) ((_c) << 8 | (_c))
472 :
473 : NS_IMETHODIMP
474 0 : nsGNOMEShellService::GetDesktopBackgroundColor(uint32_t *aColor)
475 : {
476 : nsCOMPtr<nsIGSettingsService> gsettings =
477 0 : do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
478 0 : nsCOMPtr<nsIGSettingsCollection> background_settings;
479 0 : nsAutoCString background;
480 :
481 0 : if (gsettings) {
482 0 : gsettings->GetCollectionForSchema(
483 0 : NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings));
484 0 : if (background_settings) {
485 0 : background_settings->GetString(NS_LITERAL_CSTRING(kDesktopColorGSKey),
486 0 : background);
487 : }
488 : }
489 :
490 0 : if (!background_settings) {
491 0 : nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
492 0 : if (gconf)
493 0 : gconf->GetString(NS_LITERAL_CSTRING(kDesktopColorKey), background);
494 : }
495 :
496 0 : if (background.IsEmpty()) {
497 0 : *aColor = 0;
498 0 : return NS_OK;
499 : }
500 :
501 : GdkColor color;
502 0 : gboolean success = gdk_color_parse(background.get(), &color);
503 :
504 0 : NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
505 :
506 0 : *aColor = COLOR_16_TO_8_BIT(color.red) << 16 |
507 0 : COLOR_16_TO_8_BIT(color.green) << 8 |
508 0 : COLOR_16_TO_8_BIT(color.blue);
509 0 : return NS_OK;
510 : }
511 :
512 : static void
513 0 : ColorToCString(uint32_t aColor, nsCString& aResult)
514 : {
515 : // The #rrrrggggbbbb format is used to match gdk_color_to_string()
516 0 : aResult.SetLength(13);
517 0 : char *buf = aResult.BeginWriting();
518 0 : if (!buf)
519 0 : return;
520 :
521 0 : uint16_t red = COLOR_8_TO_16_BIT((aColor >> 16) & 0xff);
522 0 : uint16_t green = COLOR_8_TO_16_BIT((aColor >> 8) & 0xff);
523 0 : uint16_t blue = COLOR_8_TO_16_BIT(aColor & 0xff);
524 :
525 0 : snprintf(buf, 14, "#%04x%04x%04x", red, green, blue);
526 : }
527 :
528 : NS_IMETHODIMP
529 0 : nsGNOMEShellService::SetDesktopBackgroundColor(uint32_t aColor)
530 : {
531 0 : NS_ASSERTION(aColor <= 0xffffff, "aColor has extra bits");
532 0 : nsAutoCString colorString;
533 0 : ColorToCString(aColor, colorString);
534 :
535 : nsCOMPtr<nsIGSettingsService> gsettings =
536 0 : do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
537 0 : if (gsettings) {
538 0 : nsCOMPtr<nsIGSettingsCollection> background_settings;
539 0 : gsettings->GetCollectionForSchema(
540 0 : NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings));
541 0 : if (background_settings) {
542 0 : background_settings->SetString(NS_LITERAL_CSTRING(kDesktopColorGSKey),
543 0 : colorString);
544 0 : return NS_OK;
545 : }
546 : }
547 :
548 0 : nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
549 :
550 0 : if (gconf) {
551 0 : gconf->SetString(NS_LITERAL_CSTRING(kDesktopColorKey), colorString);
552 : }
553 :
554 0 : return NS_OK;
555 : }
556 :
557 : NS_IMETHODIMP
558 0 : nsGNOMEShellService::OpenApplication(int32_t aApplication)
559 : {
560 0 : nsAutoCString scheme;
561 0 : if (aApplication == APPLICATION_MAIL)
562 0 : scheme.AssignLiteral("mailto");
563 0 : else if (aApplication == APPLICATION_NEWS)
564 0 : scheme.AssignLiteral("news");
565 : else
566 0 : return NS_ERROR_NOT_AVAILABLE;
567 :
568 0 : nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
569 0 : if (giovfs) {
570 0 : nsCOMPtr<nsIGIOMimeApp> gioApp;
571 0 : giovfs->GetAppForURIScheme(scheme, getter_AddRefs(gioApp));
572 0 : if (gioApp)
573 0 : return gioApp->Launch(EmptyCString());
574 : }
575 :
576 0 : nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
577 0 : if (!gconf)
578 0 : return NS_ERROR_FAILURE;
579 :
580 : bool enabled;
581 0 : nsAutoCString appCommand;
582 0 : gconf->GetAppForProtocol(scheme, &enabled, appCommand);
583 :
584 0 : if (!enabled)
585 0 : return NS_ERROR_FAILURE;
586 :
587 : // XXX we don't currently handle launching a terminal window.
588 : // If the handler requires a terminal, bail.
589 : bool requiresTerminal;
590 0 : gconf->HandlerRequiresTerminal(scheme, &requiresTerminal);
591 0 : if (requiresTerminal)
592 0 : return NS_ERROR_FAILURE;
593 :
594 : // Perform shell argument expansion
595 : int argc;
596 : char **argv;
597 0 : if (!g_shell_parse_argv(appCommand.get(), &argc, &argv, nullptr))
598 0 : return NS_ERROR_FAILURE;
599 :
600 0 : char **newArgv = new char*[argc + 1];
601 0 : int newArgc = 0;
602 :
603 : // Run through the list of arguments. Copy all of them to the new
604 : // argv except for %s, which we skip.
605 0 : for (int i = 0; i < argc; ++i) {
606 0 : if (strcmp(argv[i], "%s") != 0)
607 0 : newArgv[newArgc++] = argv[i];
608 : }
609 :
610 0 : newArgv[newArgc] = nullptr;
611 :
612 : gboolean err = g_spawn_async(nullptr, newArgv, nullptr, G_SPAWN_SEARCH_PATH,
613 0 : nullptr, nullptr, nullptr, nullptr);
614 :
615 0 : g_strfreev(argv);
616 0 : delete[] newArgv;
617 :
618 0 : return err ? NS_OK : NS_ERROR_FAILURE;
619 : }
620 :
621 : NS_IMETHODIMP
622 0 : nsGNOMEShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI)
623 : {
624 : nsresult rv;
625 : nsCOMPtr<nsIProcess> process =
626 0 : do_CreateInstance("@mozilla.org/process/util;1", &rv);
627 0 : if (NS_FAILED(rv))
628 0 : return rv;
629 :
630 0 : rv = process->Init(aApplication);
631 0 : if (NS_FAILED(rv))
632 0 : return rv;
633 :
634 0 : const nsCString spec(aURI);
635 0 : const char* specStr = spec.get();
636 0 : return process->Run(false, &specStr, 1);
637 : }
638 :
639 : NS_IMETHODIMP
640 0 : nsGNOMEShellService::GetDefaultFeedReader(nsIFile** _retval)
641 : {
642 0 : return NS_ERROR_NOT_IMPLEMENTED;
643 : }
|