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