Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/components/remote/nsRemoteService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:expandtab:shiftwidth=2:tabstop=8:
3
 */
4
/* This Source Code Form is subject to the terms of the Mozilla Public
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8
#include "nsGTKRemoteService.h"
9
#ifdef MOZ_ENABLE_DBUS
10
#include "nsDBusRemoteService.h"
11
#endif
12
#include "nsRemoteService.h"
13
14
#include <gtk/gtk.h>
15
#include <gdk/gdk.h>
16
#include <gdk/gdkx.h>
17
18
#include "nsIServiceManager.h"
19
#include "nsIAppShellService.h"
20
#include "nsAppShellCID.h"
21
#include "nsInterfaceHashtable.h"
22
#include "mozilla/ModuleUtils.h"
23
#include "nsIWeakReference.h"
24
#include "nsGTKToolkit.h"
25
#include "nsICommandLineRunner.h"
26
#include "nsCommandLine.h"
27
#include "nsString.h"
28
#include "nsIFile.h"
29
30
NS_IMPL_ISUPPORTS(nsRemoteService,
31
                  nsIRemoteService,
32
                  nsIObserver)
33
34
NS_IMETHODIMP
35
nsRemoteService::Startup(const char* aAppName, const char* aProfileName)
36
0
{
37
0
#if defined(MOZ_ENABLE_DBUS)
38
0
    nsresult rv;
39
0
    mDBusRemoteService = new nsDBusRemoteService();
40
0
    rv = mDBusRemoteService->Startup(aAppName, aProfileName);
41
0
    if (NS_FAILED(rv)) {
42
0
        mDBusRemoteService = nullptr;
43
0
    }
44
0
#endif
45
0
46
0
    if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
47
0
        mGtkRemoteService = new nsGTKRemoteService();
48
0
        mGtkRemoteService->Startup(aAppName, aProfileName);
49
0
    }
50
0
51
0
    if (!mDBusRemoteService && !mGtkRemoteService)
52
0
        return NS_ERROR_FAILURE;
53
0
54
0
    nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
55
0
    if (obs) {
56
0
        obs->AddObserver(this, "xpcom-shutdown", false);
57
0
        obs->AddObserver(this, "quit-application", false);
58
0
    }
59
0
60
0
    return NS_OK;
61
0
}
62
63
NS_IMETHODIMP
64
nsRemoteService::RegisterWindow(mozIDOMWindow* aWindow)
65
0
{
66
0
    // Note: RegisterWindow() is not implemented/needed by DBus service.
67
0
    if (mGtkRemoteService) {
68
0
        mGtkRemoteService->RegisterWindow(aWindow);
69
0
    }
70
0
    return NS_OK;
71
0
}
72
73
NS_IMETHODIMP
74
nsRemoteService::Shutdown()
75
0
{
76
0
#if defined(MOZ_ENABLE_DBUS)
77
0
    if (mDBusRemoteService) {
78
0
        mDBusRemoteService->Shutdown();
79
0
        mDBusRemoteService = nullptr;
80
0
    }
81
0
#endif
82
0
    if (mGtkRemoteService) {
83
0
        mGtkRemoteService->Shutdown();
84
0
        mGtkRemoteService = nullptr;
85
0
    }
86
0
    return NS_OK;
87
0
}
88
89
nsRemoteService::~nsRemoteService()
90
0
{
91
0
    Shutdown();
92
0
}
93
94
NS_IMETHODIMP
95
nsRemoteService::Observe(nsISupports* aSubject,
96
                          const char *aTopic,
97
                          const char16_t *aData)
98
0
{
99
0
    // This can be xpcom-shutdown or quit-application, but it's the same either
100
0
    // way.
101
0
    Shutdown();
102
0
    return NS_OK;
103
0
}
104
105
// Set desktop startup ID to the passed ID, if there is one, so that any created
106
// windows get created with the right window manager metadata, and any windows
107
// that get new tabs and are activated also get the right WM metadata.
108
// The timestamp will be used if there is no desktop startup ID, or if we're
109
// raising an existing window rather than showing a new window for the first time.
110
void
111
nsRemoteService::SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID,
112
0
                                                uint32_t aTimestamp) {
113
0
  nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
114
0
  if (!toolkit)
115
0
    return;
116
0
117
0
  if (!aDesktopStartupID.IsEmpty()) {
118
0
    toolkit->SetDesktopStartupID(aDesktopStartupID);
119
0
  }
120
0
121
0
  toolkit->SetFocusTimestamp(aTimestamp);
122
0
}
123
124
static bool
125
FindExtensionParameterInCommand(const char* aParameterName,
126
                                const nsACString& aCommand,
127
                                char aSeparator,
128
                                nsACString* aValue)
129
0
{
130
0
  nsAutoCString searchFor;
131
0
  searchFor.Append(aSeparator);
132
0
  searchFor.Append(aParameterName);
133
0
  searchFor.Append('=');
134
0
135
0
  nsACString::const_iterator start, end;
136
0
  aCommand.BeginReading(start);
137
0
  aCommand.EndReading(end);
138
0
  if (!FindInReadable(searchFor, start, end))
139
0
    return false;
140
0
141
0
  nsACString::const_iterator charStart, charEnd;
142
0
  charStart = end;
143
0
  aCommand.EndReading(charEnd);
144
0
  nsACString::const_iterator idStart = charStart, idEnd;
145
0
  if (FindCharInReadable(aSeparator, charStart, charEnd)) {
146
0
    idEnd = charStart;
147
0
  } else {
148
0
    idEnd = charEnd;
149
0
  }
150
0
  *aValue = nsDependentCSubstring(idStart, idEnd);
151
0
  return true;
152
0
}
153
154
const char*
155
nsRemoteService::HandleCommandLine(const char* aBuffer, nsIDOMWindow* aWindow,
156
                                   uint32_t aTimestamp)
157
0
{
158
0
  nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
159
0
160
0
  // the commandline property is constructed as an array of int32_t
161
0
  // followed by a series of null-terminated strings:
162
0
  //
163
0
  // [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
164
0
  // (offset is from the beginning of the buffer)
165
0
166
0
  int32_t argc = TO_LITTLE_ENDIAN32(*reinterpret_cast<const int32_t*>(aBuffer));
167
0
  const char *wd   = aBuffer + ((argc + 1) * sizeof(int32_t));
168
0
169
0
  nsCOMPtr<nsIFile> lf;
170
0
  nsresult rv = NS_NewNativeLocalFile(nsDependentCString(wd), true,
171
0
                                      getter_AddRefs(lf));
172
0
  if (NS_FAILED(rv))
173
0
    return "509 internal error";
174
0
175
0
  nsAutoCString desktopStartupID;
176
0
177
0
  const char **argv = (const char**) malloc(sizeof(char*) * argc);
178
0
  if (!argv) return "509 internal error";
179
0
180
0
  const int32_t *offset = reinterpret_cast<const int32_t*>(aBuffer) + 1;
181
0
182
0
  for (int i = 0; i < argc; ++i) {
183
0
    argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]);
184
0
185
0
    if (i == 0) {
186
0
      nsDependentCString cmd(argv[0]);
187
0
      FindExtensionParameterInCommand("DESKTOP_STARTUP_ID",
188
0
                                      cmd, ' ',
189
0
                                      &desktopStartupID);
190
0
    }
191
0
  }
192
0
193
0
  rv = cmdline->Init(argc, argv, lf, nsICommandLine::STATE_REMOTE_AUTO);
194
0
195
0
  free (argv);
196
0
  if (NS_FAILED(rv)) {
197
0
    return "509 internal error";
198
0
  }
199
0
200
0
  if (aWindow)
201
0
    cmdline->SetWindowContext(aWindow);
202
0
203
0
  SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
204
0
205
0
  rv = cmdline->Run();
206
0
207
0
  if (NS_ERROR_ABORT == rv)
208
0
    return "500 command not parseable";
209
0
210
0
  if (NS_FAILED(rv))
211
0
    return "509 internal error";
212
0
213
0
  return "200 executed command";
214
0
}
215
216
// {C0773E90-5799-4eff-AD03-3EBCD85624AC}
217
#define NS_REMOTESERVICE_CID \
218
  { 0xc0773e90, 0x5799, 0x4eff, { 0xad, 0x3, 0x3e, 0xbc, 0xd8, 0x56, 0x24, 0xac } }
219
220
NS_GENERIC_FACTORY_CONSTRUCTOR(nsRemoteService)
221
NS_DEFINE_NAMED_CID(NS_REMOTESERVICE_CID);
222
223
static const mozilla::Module::CIDEntry kRemoteCIDs[] = {
224
  { &kNS_REMOTESERVICE_CID, false, nullptr, nsRemoteServiceConstructor },
225
  { nullptr }
226
};
227
228
static const mozilla::Module::ContractIDEntry kRemoteContracts[] = {
229
  { "@mozilla.org/toolkit/remote-service;1", &kNS_REMOTESERVICE_CID },
230
  { nullptr }
231
};
232
233
static const mozilla::Module kRemoteModule = {
234
  mozilla::Module::kVersion,
235
  kRemoteCIDs,
236
  kRemoteContracts
237
};
238
239
NSMODULE_DEFN(RemoteServiceModule) = &kRemoteModule;