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 "nsGIOService.h"
7 #include "nsString.h"
8 #include "nsIURI.h"
9 #include "nsTArray.h"
10 #include "nsIStringEnumerator.h"
11 #include "nsAutoPtr.h"
12 #include "nsIMIMEInfo.h"
13 #include "nsComponentManagerUtils.h"
14 #include "nsArray.h"
15 #include "nsIFile.h"
16 #include "nsPrintfCString.h"
17
18 #include <gio/gio.h>
19 #include <gtk/gtk.h>
20 #ifdef MOZ_ENABLE_DBUS
21 #include <dbus/dbus-glib.h>
22 #include <dbus/dbus-glib-lowlevel.h>
23 #endif
24
25 // We use the same code as gtk_should_use_portal() to detect if we're in flatpak
26 // env
27 // https://github.com/GNOME/gtk/blob/e0ce028c88858b96aeda9e41734a39a3a04f705d/gtk/gtkprivate.c#L272
GetShouldUseFlatpakPortal()28 static bool GetShouldUseFlatpakPortal() {
29 bool shouldUsePortal;
30 char* path;
31 path = g_build_filename(g_get_user_runtime_dir(), "flatpak-info", nullptr);
32 if (g_file_test(path, G_FILE_TEST_EXISTS)) {
33 shouldUsePortal = true;
34 } else {
35 shouldUsePortal = (g_getenv("GTK_USE_PORTAL") != nullptr);
36 }
37 g_free(path);
38 return shouldUsePortal;
39 }
40
ShouldUseFlatpakPortal()41 static bool ShouldUseFlatpakPortal() {
42 static bool sShouldUseFlatpakPortal = GetShouldUseFlatpakPortal();
43 return sShouldUseFlatpakPortal;
44 }
45
46 class nsFlatpakHandlerApp : public nsIHandlerApp {
47 public:
48 NS_DECL_ISUPPORTS
49 NS_DECL_NSIHANDLERAPP
50 nsFlatpakHandlerApp() = default;
51
52 private:
53 virtual ~nsFlatpakHandlerApp() = default;
54 };
55
NS_IMPL_ISUPPORTS(nsFlatpakHandlerApp,nsIHandlerApp)56 NS_IMPL_ISUPPORTS(nsFlatpakHandlerApp, nsIHandlerApp)
57
58 NS_IMETHODIMP
59 nsFlatpakHandlerApp::GetName(nsAString& aName) {
60 aName.AssignLiteral("System Handler");
61 return NS_OK;
62 }
63
64 NS_IMETHODIMP
SetName(const nsAString & aName)65 nsFlatpakHandlerApp::SetName(const nsAString& aName) {
66 // We don't implement SetName because flatpak system handler name is fixed
67 return NS_OK;
68 }
69
70 NS_IMETHODIMP
GetDetailedDescription(nsAString & aDetailedDescription)71 nsFlatpakHandlerApp::GetDetailedDescription(nsAString& aDetailedDescription) {
72 return NS_ERROR_NOT_IMPLEMENTED;
73 }
74
75 NS_IMETHODIMP
SetDetailedDescription(const nsAString & aDetailedDescription)76 nsFlatpakHandlerApp::SetDetailedDescription(
77 const nsAString& aDetailedDescription) {
78 return NS_ERROR_NOT_IMPLEMENTED;
79 }
80
81 NS_IMETHODIMP
Equals(nsIHandlerApp * aHandlerApp,bool * _retval)82 nsFlatpakHandlerApp::Equals(nsIHandlerApp* aHandlerApp, bool* _retval) {
83 return NS_ERROR_NOT_IMPLEMENTED;
84 }
85
86 NS_IMETHODIMP
LaunchWithURI(nsIURI * aUri,nsIInterfaceRequestor * aRequestor)87 nsFlatpakHandlerApp::LaunchWithURI(nsIURI* aUri,
88 nsIInterfaceRequestor* aRequestor) {
89 nsCString spec;
90 aUri->GetSpec(spec);
91 GError* error = nullptr;
92
93 // The TMPDIR where files are downloaded when user choose to open them
94 // needs to be accessible from sandbox and host. The default settings
95 // TMPDIR=/tmp is accessible only to the sandbox. That can be the reason
96 // why the gtk_show_uri fails there.
97 // The workaround is to set TMPDIR environment variable in sandbox to
98 // $XDG_CACHE_HOME/tmp before executing Firefox.
99 gtk_show_uri(nullptr, spec.get(), GDK_CURRENT_TIME, &error);
100 if (error) {
101 NS_WARNING(
102 nsPrintfCString("Cannot launch flatpak handler: %s", error->message)
103 .get());
104 g_error_free(error);
105 return NS_ERROR_FAILURE;
106 }
107 return NS_OK;
108 }
109
110 /**
111 * Get command without any additional arguments
112 * @param aCommandWithArguments full commandline input string
113 * @param aCommand string for storing command without arguments
114 * @return NS_ERROR_FAILURE when unable to parse commandline
115 */
GetCommandFromCommandline(nsACString const & aCommandWithArguments,nsACString & aCommand)116 static nsresult GetCommandFromCommandline(
117 nsACString const& aCommandWithArguments, nsACString& aCommand) {
118 GError* error = nullptr;
119 gchar** argv = nullptr;
120 if (!g_shell_parse_argv(aCommandWithArguments.BeginReading(), nullptr, &argv,
121 &error) ||
122 !argv[0]) {
123 g_warning("Cannot parse command with arguments: %s", error->message);
124 g_error_free(error);
125 g_strfreev(argv);
126 return NS_ERROR_FAILURE;
127 }
128 aCommand.Assign(argv[0]);
129 g_strfreev(argv);
130 return NS_OK;
131 }
132
133 class nsGIOMimeApp final : public nsIGIOMimeApp {
134 public:
135 NS_DECL_ISUPPORTS
136 NS_DECL_NSIHANDLERAPP
137 NS_DECL_NSIGIOMIMEAPP
138
nsGIOMimeApp(GAppInfo * aApp)139 explicit nsGIOMimeApp(GAppInfo* aApp) : mApp(aApp) {}
140
141 private:
~nsGIOMimeApp()142 ~nsGIOMimeApp() { g_object_unref(mApp); }
143
144 GAppInfo* mApp;
145 };
146
NS_IMPL_ISUPPORTS(nsGIOMimeApp,nsIGIOMimeApp,nsIHandlerApp)147 NS_IMPL_ISUPPORTS(nsGIOMimeApp, nsIGIOMimeApp, nsIHandlerApp)
148
149 NS_IMETHODIMP
150 nsGIOMimeApp::GetId(nsACString& aId) {
151 aId.Assign(g_app_info_get_id(mApp));
152 return NS_OK;
153 }
154
155 NS_IMETHODIMP
GetName(nsAString & aName)156 nsGIOMimeApp::GetName(nsAString& aName) {
157 aName.Assign(NS_ConvertUTF8toUTF16(g_app_info_get_name(mApp)));
158 return NS_OK;
159 }
160
161 NS_IMETHODIMP
SetName(const nsAString & aName)162 nsGIOMimeApp::SetName(const nsAString& aName) {
163 // We don't implement SetName because we're using mGIOMimeApp instance for
164 // obtaining application name
165 return NS_OK;
166 }
167
168 NS_IMETHODIMP
GetCommand(nsACString & aCommand)169 nsGIOMimeApp::GetCommand(nsACString& aCommand) {
170 const char* cmd = g_app_info_get_commandline(mApp);
171 if (!cmd) return NS_ERROR_FAILURE;
172 aCommand.Assign(cmd);
173 return NS_OK;
174 }
175
176 NS_IMETHODIMP
GetExpectsURIs(int32_t * aExpects)177 nsGIOMimeApp::GetExpectsURIs(int32_t* aExpects) {
178 *aExpects = g_app_info_supports_uris(mApp);
179 return NS_OK;
180 }
181
182 NS_IMETHODIMP
GetDetailedDescription(nsAString & aDetailedDescription)183 nsGIOMimeApp::GetDetailedDescription(nsAString& aDetailedDescription) {
184 return NS_ERROR_NOT_IMPLEMENTED;
185 }
186
187 NS_IMETHODIMP
SetDetailedDescription(const nsAString & aDetailedDescription)188 nsGIOMimeApp::SetDetailedDescription(const nsAString& aDetailedDescription) {
189 return NS_ERROR_NOT_IMPLEMENTED;
190 }
191
192 NS_IMETHODIMP
Equals(nsIHandlerApp * aHandlerApp,bool * _retval)193 nsGIOMimeApp::Equals(nsIHandlerApp* aHandlerApp, bool* _retval) {
194 if (!aHandlerApp) return NS_ERROR_FAILURE;
195
196 // Compare with nsILocalHandlerApp instance by name
197 nsCOMPtr<nsILocalHandlerApp> localHandlerApp = do_QueryInterface(aHandlerApp);
198 if (localHandlerApp) {
199 nsAutoString theirName;
200 nsAutoString thisName;
201 GetName(thisName);
202 localHandlerApp->GetName(theirName);
203 *_retval = thisName.Equals(theirName);
204 return NS_OK;
205 }
206
207 // Compare with nsIGIOMimeApp instance by command with stripped arguments
208 nsCOMPtr<nsIGIOMimeApp> gioMimeApp = do_QueryInterface(aHandlerApp);
209 if (gioMimeApp) {
210 nsAutoCString thisCommandline, thisCommand;
211 nsresult rv = GetCommand(thisCommandline);
212 NS_ENSURE_SUCCESS(rv, rv);
213
214 rv = GetCommandFromCommandline(thisCommandline, thisCommand);
215 NS_ENSURE_SUCCESS(rv, rv);
216
217 nsAutoCString theirCommandline, theirCommand;
218 gioMimeApp->GetCommand(theirCommandline);
219 NS_ENSURE_SUCCESS(rv, rv);
220
221 rv = GetCommandFromCommandline(theirCommandline, theirCommand);
222 NS_ENSURE_SUCCESS(rv, rv);
223
224 *_retval = thisCommand.Equals(theirCommand);
225 return NS_OK;
226 }
227
228 // We can only compare with nsILocalHandlerApp and nsGIOMimeApp
229 *_retval = false;
230 return NS_OK;
231 }
232
233 NS_IMETHODIMP
LaunchWithURI(nsIURI * aUri,nsIInterfaceRequestor * aRequestor)234 nsGIOMimeApp::LaunchWithURI(nsIURI* aUri, nsIInterfaceRequestor* aRequestor) {
235 GList uris = {0};
236 nsCString spec;
237 aUri->GetSpec(spec);
238 // nsPromiseFlatCString flatUri(aUri);
239 uris.data = const_cast<char*>(spec.get());
240
241 GError* error = nullptr;
242 gboolean result = g_app_info_launch_uris(mApp, &uris, nullptr, &error);
243
244 if (!result) {
245 g_warning("Cannot launch application: %s", error->message);
246 g_error_free(error);
247 return NS_ERROR_FAILURE;
248 }
249
250 return NS_OK;
251 }
252
253 class GIOUTF8StringEnumerator final : public nsIUTF8StringEnumerator {
254 ~GIOUTF8StringEnumerator() = default;
255
256 public:
GIOUTF8StringEnumerator()257 GIOUTF8StringEnumerator() : mIndex(0) {}
258
259 NS_DECL_ISUPPORTS
260 NS_DECL_NSIUTF8STRINGENUMERATOR
261
262 nsTArray<nsCString> mStrings;
263 uint32_t mIndex;
264 };
265
NS_IMPL_ISUPPORTS(GIOUTF8StringEnumerator,nsIUTF8StringEnumerator)266 NS_IMPL_ISUPPORTS(GIOUTF8StringEnumerator, nsIUTF8StringEnumerator)
267
268 NS_IMETHODIMP
269 GIOUTF8StringEnumerator::HasMore(bool* aResult) {
270 *aResult = mIndex < mStrings.Length();
271 return NS_OK;
272 }
273
274 NS_IMETHODIMP
GetNext(nsACString & aResult)275 GIOUTF8StringEnumerator::GetNext(nsACString& aResult) {
276 if (mIndex >= mStrings.Length()) return NS_ERROR_UNEXPECTED;
277
278 aResult.Assign(mStrings[mIndex]);
279 ++mIndex;
280 return NS_OK;
281 }
282
283 NS_IMETHODIMP
GetSupportedURISchemes(nsIUTF8StringEnumerator ** aSchemes)284 nsGIOMimeApp::GetSupportedURISchemes(nsIUTF8StringEnumerator** aSchemes) {
285 *aSchemes = nullptr;
286
287 RefPtr<GIOUTF8StringEnumerator> array = new GIOUTF8StringEnumerator();
288 NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
289
290 GVfs* gvfs = g_vfs_get_default();
291
292 if (!gvfs) {
293 g_warning("Cannot get GVfs object.");
294 return NS_ERROR_OUT_OF_MEMORY;
295 }
296
297 const gchar* const* uri_schemes = g_vfs_get_supported_uri_schemes(gvfs);
298
299 while (*uri_schemes != nullptr) {
300 if (!array->mStrings.AppendElement(*uri_schemes)) {
301 return NS_ERROR_OUT_OF_MEMORY;
302 }
303 uri_schemes++;
304 }
305
306 array.forget(aSchemes);
307 return NS_OK;
308 }
309
310 NS_IMETHODIMP
SetAsDefaultForMimeType(nsACString const & aMimeType)311 nsGIOMimeApp::SetAsDefaultForMimeType(nsACString const& aMimeType) {
312 char* content_type =
313 g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
314 if (!content_type) return NS_ERROR_FAILURE;
315 GError* error = nullptr;
316 g_app_info_set_as_default_for_type(mApp, content_type, &error);
317 if (error) {
318 g_warning("Cannot set application as default for MIME type (%s): %s",
319 PromiseFlatCString(aMimeType).get(), error->message);
320 g_error_free(error);
321 g_free(content_type);
322 return NS_ERROR_FAILURE;
323 }
324
325 g_free(content_type);
326 return NS_OK;
327 }
328 /**
329 * Set default application for files with given extensions
330 * @param fileExts string of space separated extensions
331 * @return NS_OK when application was set as default for given extensions,
332 * NS_ERROR_FAILURE otherwise
333 */
334 NS_IMETHODIMP
SetAsDefaultForFileExtensions(nsACString const & fileExts)335 nsGIOMimeApp::SetAsDefaultForFileExtensions(nsACString const& fileExts) {
336 GError* error = nullptr;
337 char* extensions = g_strdup(PromiseFlatCString(fileExts).get());
338 char* ext_pos = extensions;
339 char* space_pos;
340
341 while ((space_pos = strchr(ext_pos, ' ')) || (*ext_pos != '\0')) {
342 if (space_pos) {
343 *space_pos = '\0';
344 }
345 g_app_info_set_as_default_for_extension(mApp, ext_pos, &error);
346 if (error) {
347 g_warning("Cannot set application as default for extension (%s): %s",
348 ext_pos, error->message);
349 g_error_free(error);
350 g_free(extensions);
351 return NS_ERROR_FAILURE;
352 }
353 if (space_pos) {
354 ext_pos = space_pos + 1;
355 } else {
356 *ext_pos = '\0';
357 }
358 }
359 g_free(extensions);
360 return NS_OK;
361 }
362
363 /**
364 * Set default application for URI's of a particular scheme
365 * @param aURIScheme string containing the URI scheme
366 * @return NS_OK when application was set as default for URI scheme,
367 * NS_ERROR_FAILURE otherwise
368 */
369 NS_IMETHODIMP
SetAsDefaultForURIScheme(nsACString const & aURIScheme)370 nsGIOMimeApp::SetAsDefaultForURIScheme(nsACString const& aURIScheme) {
371 GError* error = nullptr;
372 nsAutoCString contentType("x-scheme-handler/");
373 contentType.Append(aURIScheme);
374
375 g_app_info_set_as_default_for_type(mApp, contentType.get(), &error);
376 if (error) {
377 g_warning("Cannot set application as default for URI scheme (%s): %s",
378 PromiseFlatCString(aURIScheme).get(), error->message);
379 g_error_free(error);
380 return NS_ERROR_FAILURE;
381 }
382
383 return NS_OK;
384 }
385
NS_IMPL_ISUPPORTS(nsGIOService,nsIGIOService)386 NS_IMPL_ISUPPORTS(nsGIOService, nsIGIOService)
387
388 NS_IMETHODIMP
389 nsGIOService::GetMimeTypeFromExtension(const nsACString& aExtension,
390 nsACString& aMimeType) {
391 nsAutoCString fileExtToUse("file.");
392 fileExtToUse.Append(aExtension);
393
394 gboolean result_uncertain;
395 char* content_type =
396 g_content_type_guess(fileExtToUse.get(), nullptr, 0, &result_uncertain);
397 if (!content_type) return NS_ERROR_FAILURE;
398
399 char* mime_type = g_content_type_get_mime_type(content_type);
400 if (!mime_type) {
401 g_free(content_type);
402 return NS_ERROR_FAILURE;
403 }
404
405 aMimeType.Assign(mime_type);
406
407 g_free(mime_type);
408 g_free(content_type);
409
410 return NS_OK;
411 }
412 // used in nsGNOMERegistry
413 // -----------------------------------------------------------------------------
414 NS_IMETHODIMP
GetAppForURIScheme(const nsACString & aURIScheme,nsIHandlerApp ** aApp)415 nsGIOService::GetAppForURIScheme(const nsACString& aURIScheme,
416 nsIHandlerApp** aApp) {
417 *aApp = nullptr;
418
419 // Application in flatpak sandbox does not have access to the list
420 // of installed applications on the system. We use generic
421 // nsFlatpakHandlerApp which forwards launch call to the system.
422 if (ShouldUseFlatpakPortal()) {
423 nsFlatpakHandlerApp* mozApp = new nsFlatpakHandlerApp();
424 NS_ADDREF(*aApp = mozApp);
425 return NS_OK;
426 }
427
428 GAppInfo* app_info = g_app_info_get_default_for_uri_scheme(
429 PromiseFlatCString(aURIScheme).get());
430 if (app_info) {
431 nsGIOMimeApp* mozApp = new nsGIOMimeApp(app_info);
432 NS_ADDREF(*aApp = mozApp);
433 } else {
434 return NS_ERROR_FAILURE;
435 }
436 return NS_OK;
437 }
438
439 NS_IMETHODIMP
GetAppsForURIScheme(const nsACString & aURIScheme,nsIMutableArray ** aResult)440 nsGIOService::GetAppsForURIScheme(const nsACString& aURIScheme,
441 nsIMutableArray** aResult) {
442 // We don't need to return the nsFlatpakHandlerApp here because
443 // it would be skipped by the callers anyway.
444 // The preferred handler is provided by GetAppForURIScheme.
445 // This method returns all possible application handlers
446 // including preferred one. The callers skips the preferred
447 // handler in this list to avoid duplicate records in the list
448 // they create.
449 nsCOMPtr<nsIMutableArray> handlersArray =
450 do_CreateInstance(NS_ARRAY_CONTRACTID);
451
452 nsAutoCString contentType("x-scheme-handler/");
453 contentType.Append(aURIScheme);
454
455 GList* appInfoList = g_app_info_get_all_for_type(contentType.get());
456 // g_app_info_get_all_for_type returns NULL when no appinfo is found
457 // or error occurs (contentType is NULL). We are fine with empty app list
458 // and we're sure that contentType is not NULL, so we won't return failure.
459 if (appInfoList) {
460 GList* appInfo = appInfoList;
461 while (appInfo) {
462 nsCOMPtr<nsIGIOMimeApp> mimeApp =
463 new nsGIOMimeApp(G_APP_INFO(appInfo->data));
464 handlersArray->AppendElement(mimeApp);
465 appInfo = appInfo->next;
466 }
467 g_list_free(appInfoList);
468 }
469 NS_ADDREF(*aResult = handlersArray);
470 return NS_OK;
471 }
472
473 NS_IMETHODIMP
GetAppForMimeType(const nsACString & aMimeType,nsIHandlerApp ** aApp)474 nsGIOService::GetAppForMimeType(const nsACString& aMimeType,
475 nsIHandlerApp** aApp) {
476 *aApp = nullptr;
477
478 // Flatpak does not reveal installed application to the sandbox,
479 // we need to create generic system handler.
480 if (ShouldUseFlatpakPortal()) {
481 nsFlatpakHandlerApp* mozApp = new nsFlatpakHandlerApp();
482 NS_ADDREF(*aApp = mozApp);
483 return NS_OK;
484 }
485
486 char* content_type =
487 g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
488 if (!content_type) return NS_ERROR_FAILURE;
489
490 GAppInfo* app_info = g_app_info_get_default_for_type(content_type, false);
491 if (app_info) {
492 nsGIOMimeApp* mozApp = new nsGIOMimeApp(app_info);
493 NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
494 NS_ADDREF(*aApp = mozApp);
495 } else {
496 g_free(content_type);
497 return NS_ERROR_FAILURE;
498 }
499 g_free(content_type);
500 return NS_OK;
501 }
502
503 NS_IMETHODIMP
GetDescriptionForMimeType(const nsACString & aMimeType,nsACString & aDescription)504 nsGIOService::GetDescriptionForMimeType(const nsACString& aMimeType,
505 nsACString& aDescription) {
506 char* content_type =
507 g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
508 if (!content_type) return NS_ERROR_FAILURE;
509
510 char* desc = g_content_type_get_description(content_type);
511 if (!desc) {
512 g_free(content_type);
513 return NS_ERROR_FAILURE;
514 }
515
516 aDescription.Assign(desc);
517 g_free(content_type);
518 g_free(desc);
519 return NS_OK;
520 }
521
522 NS_IMETHODIMP
ShowURI(nsIURI * aURI)523 nsGIOService::ShowURI(nsIURI* aURI) {
524 nsAutoCString spec;
525 nsresult rv = aURI->GetSpec(spec);
526 NS_ENSURE_SUCCESS(rv, rv);
527 GError* error = nullptr;
528 if (!g_app_info_launch_default_for_uri(spec.get(), nullptr, &error)) {
529 g_warning("Could not launch default application for URI: %s",
530 error->message);
531 g_error_free(error);
532 return NS_ERROR_FAILURE;
533 }
534 return NS_OK;
535 }
536
537 NS_IMETHODIMP
ShowURIForInput(const nsACString & aUri)538 nsGIOService::ShowURIForInput(const nsACString& aUri) {
539 GFile* file = g_file_new_for_commandline_arg(PromiseFlatCString(aUri).get());
540 char* spec = g_file_get_uri(file);
541 nsresult rv = NS_ERROR_FAILURE;
542 GError* error = nullptr;
543
544 g_app_info_launch_default_for_uri(spec, nullptr, &error);
545 if (error) {
546 g_warning("Cannot launch default application: %s", error->message);
547 g_error_free(error);
548 } else {
549 rv = NS_OK;
550 }
551 g_object_unref(file);
552 g_free(spec);
553
554 return rv;
555 }
556
557 NS_IMETHODIMP
OrgFreedesktopFileManager1ShowItems(const nsACString & aPath)558 nsGIOService::OrgFreedesktopFileManager1ShowItems(const nsACString& aPath) {
559 #ifndef MOZ_ENABLE_DBUS
560 return NS_ERROR_FAILURE;
561 #else
562 GError* error = nullptr;
563 static bool org_freedesktop_FileManager1_exists = true;
564
565 if (!org_freedesktop_FileManager1_exists) {
566 return NS_ERROR_NOT_AVAILABLE;
567 }
568
569 DBusGConnection* dbusGConnection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
570
571 if (!dbusGConnection) {
572 if (error) {
573 g_printerr("Failed to open connection to session bus: %s\n",
574 error->message);
575 g_error_free(error);
576 }
577 return NS_ERROR_FAILURE;
578 }
579
580 char* uri =
581 g_filename_to_uri(PromiseFlatCString(aPath).get(), nullptr, nullptr);
582 if (uri == nullptr) {
583 return NS_ERROR_FAILURE;
584 }
585
586 DBusConnection* dbusConnection =
587 dbus_g_connection_get_connection(dbusGConnection);
588 // Make sure we do not exit the entire program if DBus connection get lost.
589 dbus_connection_set_exit_on_disconnect(dbusConnection, false);
590
591 DBusGProxy* dbusGProxy = dbus_g_proxy_new_for_name(
592 dbusGConnection, "org.freedesktop.FileManager1",
593 "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1");
594
595 const char* uris[2] = {uri, nullptr};
596 gboolean rv_dbus_call =
597 dbus_g_proxy_call(dbusGProxy, "ShowItems", nullptr, G_TYPE_STRV, uris,
598 G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
599
600 g_object_unref(dbusGProxy);
601 dbus_g_connection_unref(dbusGConnection);
602 g_free(uri);
603
604 if (!rv_dbus_call) {
605 org_freedesktop_FileManager1_exists = false;
606 return NS_ERROR_NOT_AVAILABLE;
607 }
608
609 return NS_OK;
610 #endif
611 }
612
613 /**
614 * Find GIO Mime App from given commandline.
615 * This is different from CreateAppFromCommand because instead of creating the
616 * GIO Mime App in case it's not found in the GIO application list, the method
617 * returns error.
618 * @param aCmd command with parameters used to start the application
619 * @return NS_OK when application is found, NS_ERROR_NOT_AVAILABLE otherwise
620 */
621 NS_IMETHODIMP
FindAppFromCommand(nsACString const & aCmd,nsIGIOMimeApp ** aAppInfo)622 nsGIOService::FindAppFromCommand(nsACString const& aCmd,
623 nsIGIOMimeApp** aAppInfo) {
624 GAppInfo *app_info = nullptr, *app_info_from_list = nullptr;
625 GList* apps = g_app_info_get_all();
626 GList* apps_p = apps;
627
628 // Try to find relevant and existing GAppInfo in all installed application
629 // We do this by comparing each GAppInfo's executable with out own
630 while (apps_p) {
631 app_info_from_list = (GAppInfo*)apps_p->data;
632 if (!app_info) {
633 // If the executable is not absolute, get it's full path
634 char* executable =
635 g_find_program_in_path(g_app_info_get_executable(app_info_from_list));
636
637 if (executable &&
638 strcmp(executable, PromiseFlatCString(aCmd).get()) == 0) {
639 g_object_ref(app_info_from_list);
640 app_info = app_info_from_list;
641 }
642 g_free(executable);
643 }
644
645 g_object_unref(app_info_from_list);
646 apps_p = apps_p->next;
647 }
648 g_list_free(apps);
649 if (app_info) {
650 nsGIOMimeApp* app = new nsGIOMimeApp(app_info);
651 NS_ENSURE_TRUE(app, NS_ERROR_OUT_OF_MEMORY);
652 NS_ADDREF(*aAppInfo = app);
653 return NS_OK;
654 }
655
656 *aAppInfo = nullptr;
657 return NS_ERROR_NOT_AVAILABLE;
658 }
659
660 /**
661 * Create application info for specified command and application name.
662 * Command arguments are ignored and the "%u" is always added.
663 * @param cmd command to execute
664 * @param appName application name
665 * @param appInfo location where created GAppInfo is stored
666 * @return NS_OK when object is created, NS_ERROR_FILE_NOT_FOUND when executable
667 * is not found in the system path or NS_ERROR_FAILURE otherwise.
668 */
669 NS_IMETHODIMP
CreateAppFromCommand(nsACString const & cmd,nsACString const & appName,nsIGIOMimeApp ** appInfo)670 nsGIOService::CreateAppFromCommand(nsACString const& cmd,
671 nsACString const& appName,
672 nsIGIOMimeApp** appInfo) {
673 GError* error = nullptr;
674 *appInfo = nullptr;
675
676 // Using G_APP_INFO_CREATE_SUPPORTS_URIS calling
677 // g_app_info_create_from_commandline appends %u to the cmd even when cmd
678 // already contains this parameter. To avoid that we're going to remove
679 // arguments before passing to it.
680 nsAutoCString commandWithoutArgs;
681 nsresult rv = GetCommandFromCommandline(cmd, commandWithoutArgs);
682 NS_ENSURE_SUCCESS(rv, rv);
683 GAppInfo* app_info = g_app_info_create_from_commandline(
684 commandWithoutArgs.BeginReading(), PromiseFlatCString(appName).get(),
685 G_APP_INFO_CREATE_SUPPORTS_URIS, &error);
686 if (!app_info) {
687 g_warning("Cannot create application info from command: %s",
688 error->message);
689 g_error_free(error);
690 return NS_ERROR_FAILURE;
691 }
692
693 // Check if executable exist in path
694 gchar* executableWithFullPath =
695 g_find_program_in_path(commandWithoutArgs.BeginReading());
696 if (!executableWithFullPath) {
697 return NS_ERROR_FILE_NOT_FOUND;
698 }
699 g_free(executableWithFullPath);
700
701 nsGIOMimeApp* mozApp = new nsGIOMimeApp(app_info);
702 NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
703 NS_ADDREF(*appInfo = mozApp);
704 return NS_OK;
705 }
706