Coverage Report

Created: 2018-09-25 14:53

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