toolkit/components/remote/nsXRemoteService.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:expandtab:shiftwidth=2:tabstop=8:
michael@0 3 */
michael@0 4 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 #include "mozilla/ArrayUtils.h"
michael@0 9
michael@0 10 #include "nsXRemoteService.h"
michael@0 11 #include "nsIObserverService.h"
michael@0 12 #include "nsCOMPtr.h"
michael@0 13 #include "nsIServiceManager.h"
michael@0 14 #include "nsICommandLineRunner.h"
michael@0 15 #include "nsICommandLine.h"
michael@0 16
michael@0 17 #include "nsIBaseWindow.h"
michael@0 18 #include "nsIDocShell.h"
michael@0 19 #include "nsIFile.h"
michael@0 20 #include "nsIServiceManager.h"
michael@0 21 #include "nsIWeakReference.h"
michael@0 22 #include "nsIWidget.h"
michael@0 23 #include "nsIAppShellService.h"
michael@0 24 #include "nsAppShellCID.h"
michael@0 25 #include "nsPIDOMWindow.h"
michael@0 26 #include "mozilla/X11Util.h"
michael@0 27
michael@0 28 #include "nsCOMPtr.h"
michael@0 29 #include "nsString.h"
michael@0 30 #include "prprf.h"
michael@0 31 #include "prenv.h"
michael@0 32 #include "nsCRT.h"
michael@0 33
michael@0 34 #include "nsXULAppAPI.h"
michael@0 35
michael@0 36 #include <X11/Xlib.h>
michael@0 37 #include <X11/Xatom.h>
michael@0 38
michael@0 39 using namespace mozilla;
michael@0 40
michael@0 41 #define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
michael@0 42 #define MOZILLA_LOCK_PROP "_MOZILLA_LOCK"
michael@0 43 #define MOZILLA_COMMAND_PROP "_MOZILLA_COMMAND"
michael@0 44 #define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE"
michael@0 45 #define MOZILLA_USER_PROP "_MOZILLA_USER"
michael@0 46 #define MOZILLA_PROFILE_PROP "_MOZILLA_PROFILE"
michael@0 47 #define MOZILLA_PROGRAM_PROP "_MOZILLA_PROGRAM"
michael@0 48 #define MOZILLA_COMMANDLINE_PROP "_MOZILLA_COMMANDLINE"
michael@0 49
michael@0 50 const unsigned char kRemoteVersion[] = "5.1";
michael@0 51
michael@0 52 #ifdef IS_BIG_ENDIAN
michael@0 53 #define TO_LITTLE_ENDIAN32(x) \
michael@0 54 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
michael@0 55 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
michael@0 56 #else
michael@0 57 #define TO_LITTLE_ENDIAN32(x) (x)
michael@0 58 #endif
michael@0 59
michael@0 60 // Minimize the roundtrips to the X server by getting all the atoms at once
michael@0 61 static const char *XAtomNames[] = {
michael@0 62 MOZILLA_VERSION_PROP,
michael@0 63 MOZILLA_LOCK_PROP,
michael@0 64 MOZILLA_COMMAND_PROP,
michael@0 65 MOZILLA_RESPONSE_PROP,
michael@0 66 MOZILLA_USER_PROP,
michael@0 67 MOZILLA_PROFILE_PROP,
michael@0 68 MOZILLA_PROGRAM_PROP,
michael@0 69 MOZILLA_COMMANDLINE_PROP
michael@0 70 };
michael@0 71 static Atom XAtoms[MOZ_ARRAY_LENGTH(XAtomNames)];
michael@0 72
michael@0 73 Atom nsXRemoteService::sMozVersionAtom;
michael@0 74 Atom nsXRemoteService::sMozLockAtom;
michael@0 75 Atom nsXRemoteService::sMozCommandAtom;
michael@0 76 Atom nsXRemoteService::sMozResponseAtom;
michael@0 77 Atom nsXRemoteService::sMozUserAtom;
michael@0 78 Atom nsXRemoteService::sMozProfileAtom;
michael@0 79 Atom nsXRemoteService::sMozProgramAtom;
michael@0 80 Atom nsXRemoteService::sMozCommandLineAtom;
michael@0 81
michael@0 82 nsXRemoteService * nsXRemoteService::sRemoteImplementation = 0;
michael@0 83
michael@0 84
michael@0 85 static bool
michael@0 86 FindExtensionParameterInCommand(const char* aParameterName,
michael@0 87 const nsACString& aCommand,
michael@0 88 char aSeparator,
michael@0 89 nsACString* aValue)
michael@0 90 {
michael@0 91 nsAutoCString searchFor;
michael@0 92 searchFor.Append(aSeparator);
michael@0 93 searchFor.Append(aParameterName);
michael@0 94 searchFor.Append('=');
michael@0 95
michael@0 96 nsACString::const_iterator start, end;
michael@0 97 aCommand.BeginReading(start);
michael@0 98 aCommand.EndReading(end);
michael@0 99 if (!FindInReadable(searchFor, start, end))
michael@0 100 return false;
michael@0 101
michael@0 102 nsACString::const_iterator charStart, charEnd;
michael@0 103 charStart = end;
michael@0 104 aCommand.EndReading(charEnd);
michael@0 105 nsACString::const_iterator idStart = charStart, idEnd;
michael@0 106 if (FindCharInReadable(aSeparator, charStart, charEnd)) {
michael@0 107 idEnd = charStart;
michael@0 108 } else {
michael@0 109 idEnd = charEnd;
michael@0 110 }
michael@0 111 *aValue = nsDependentCSubstring(idStart, idEnd);
michael@0 112 return true;
michael@0 113 }
michael@0 114
michael@0 115
michael@0 116 nsXRemoteService::nsXRemoteService()
michael@0 117 {
michael@0 118 }
michael@0 119
michael@0 120 void
michael@0 121 nsXRemoteService::XRemoteBaseStartup(const char *aAppName, const char *aProfileName)
michael@0 122 {
michael@0 123 EnsureAtoms();
michael@0 124
michael@0 125 mAppName = aAppName;
michael@0 126 ToLowerCase(mAppName);
michael@0 127
michael@0 128 mProfileName = aProfileName;
michael@0 129
michael@0 130 nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
michael@0 131 if (obs) {
michael@0 132 obs->AddObserver(this, "xpcom-shutdown", false);
michael@0 133 obs->AddObserver(this, "quit-application", false);
michael@0 134 }
michael@0 135 }
michael@0 136
michael@0 137 void
michael@0 138 nsXRemoteService::HandleCommandsFor(Window aWindowId)
michael@0 139 {
michael@0 140 // set our version
michael@0 141 XChangeProperty(mozilla::DefaultXDisplay(), aWindowId, sMozVersionAtom, XA_STRING,
michael@0 142 8, PropModeReplace, kRemoteVersion, sizeof(kRemoteVersion) - 1);
michael@0 143
michael@0 144 // get our username
michael@0 145 unsigned char *logname;
michael@0 146 logname = (unsigned char*) PR_GetEnv("LOGNAME");
michael@0 147 if (logname) {
michael@0 148 // set the property on the window if it's available
michael@0 149 XChangeProperty(mozilla::DefaultXDisplay(), aWindowId, sMozUserAtom, XA_STRING,
michael@0 150 8, PropModeReplace, logname, strlen((char*) logname));
michael@0 151 }
michael@0 152
michael@0 153 XChangeProperty(mozilla::DefaultXDisplay(), aWindowId, sMozProgramAtom, XA_STRING,
michael@0 154 8, PropModeReplace, (unsigned char*) mAppName.get(), mAppName.Length());
michael@0 155
michael@0 156 if (!mProfileName.IsEmpty()) {
michael@0 157 XChangeProperty(mozilla::DefaultXDisplay(),
michael@0 158 aWindowId, sMozProfileAtom, XA_STRING,
michael@0 159 8, PropModeReplace,
michael@0 160 (unsigned char*) mProfileName.get(), mProfileName.Length());
michael@0 161 }
michael@0 162
michael@0 163 }
michael@0 164
michael@0 165 NS_IMETHODIMP
michael@0 166 nsXRemoteService::Observe(nsISupports* aSubject,
michael@0 167 const char *aTopic,
michael@0 168 const char16_t *aData)
michael@0 169 {
michael@0 170 // This can be xpcom-shutdown or quit-application, but it's the same either
michael@0 171 // way.
michael@0 172 Shutdown();
michael@0 173 return NS_OK;
michael@0 174 }
michael@0 175
michael@0 176 bool
michael@0 177 nsXRemoteService::HandleNewProperty(XID aWindowId, Display* aDisplay,
michael@0 178 Time aEventTime,
michael@0 179 Atom aChangedAtom,
michael@0 180 nsIWeakReference* aDomWindow)
michael@0 181 {
michael@0 182
michael@0 183 nsCOMPtr<nsIDOMWindow> window (do_QueryReferent(aDomWindow));
michael@0 184
michael@0 185 if (aChangedAtom == sMozCommandAtom || aChangedAtom == sMozCommandLineAtom) {
michael@0 186 // We got a new command atom.
michael@0 187 int result;
michael@0 188 Atom actual_type;
michael@0 189 int actual_format;
michael@0 190 unsigned long nitems, bytes_after;
michael@0 191 char *data = 0;
michael@0 192
michael@0 193 result = XGetWindowProperty (aDisplay,
michael@0 194 aWindowId,
michael@0 195 aChangedAtom,
michael@0 196 0, /* long_offset */
michael@0 197 (65536 / sizeof (long)), /* long_length */
michael@0 198 True, /* atomic delete after */
michael@0 199 XA_STRING, /* req_type */
michael@0 200 &actual_type, /* actual_type return */
michael@0 201 &actual_format, /* actual_format_return */
michael@0 202 &nitems, /* nitems_return */
michael@0 203 &bytes_after, /* bytes_after_return */
michael@0 204 (unsigned char **)&data); /* prop_return
michael@0 205 (we only care
michael@0 206 about the first ) */
michael@0 207
michael@0 208 // Failed to get property off the window?
michael@0 209 if (result != Success)
michael@0 210 return false;
michael@0 211
michael@0 212 // Failed to get the data off the window or it was the wrong type?
michael@0 213 if (!data || !TO_LITTLE_ENDIAN32(*reinterpret_cast<int32_t*>(data)))
michael@0 214 return false;
michael@0 215
michael@0 216 // cool, we got the property data.
michael@0 217 const char *response = nullptr;
michael@0 218 if (aChangedAtom == sMozCommandAtom)
michael@0 219 response = HandleCommand(data, window, aEventTime);
michael@0 220 else if (aChangedAtom == sMozCommandLineAtom)
michael@0 221 response = HandleCommandLine(data, window, aEventTime);
michael@0 222
michael@0 223 // put the property onto the window as the response
michael@0 224 XChangeProperty (aDisplay, aWindowId,
michael@0 225 sMozResponseAtom, XA_STRING,
michael@0 226 8, PropModeReplace,
michael@0 227 (const unsigned char *)response,
michael@0 228 strlen (response));
michael@0 229 XFree(data);
michael@0 230 return true;
michael@0 231 }
michael@0 232
michael@0 233 else if (aChangedAtom == sMozResponseAtom) {
michael@0 234 // client accepted the response. party on wayne.
michael@0 235 return true;
michael@0 236 }
michael@0 237
michael@0 238 else if (aChangedAtom == sMozLockAtom) {
michael@0 239 // someone locked the window
michael@0 240 return true;
michael@0 241 }
michael@0 242
michael@0 243 return false;
michael@0 244 }
michael@0 245
michael@0 246 const char*
michael@0 247 nsXRemoteService::HandleCommand(char* aCommand, nsIDOMWindow* aWindow,
michael@0 248 uint32_t aTimestamp)
michael@0 249 {
michael@0 250 nsresult rv;
michael@0 251
michael@0 252 nsCOMPtr<nsICommandLineRunner> cmdline
michael@0 253 (do_CreateInstance("@mozilla.org/toolkit/command-line;1", &rv));
michael@0 254 if (NS_FAILED(rv))
michael@0 255 return "509 internal error";
michael@0 256
michael@0 257 // 1) Make sure that it looks remotely valid with parens
michael@0 258 // 2) Treat ping() immediately and specially
michael@0 259
michael@0 260 nsAutoCString command(aCommand);
michael@0 261 int32_t p1, p2;
michael@0 262 p1 = command.FindChar('(');
michael@0 263 p2 = command.FindChar(')');
michael@0 264
michael@0 265 if (p1 == kNotFound || p2 == kNotFound || p1 == 0 || p2 < p1) {
michael@0 266 return "500 command not parseable";
michael@0 267 }
michael@0 268
michael@0 269 command.Truncate(p1);
michael@0 270 command.Trim(" ", true, true);
michael@0 271 ToLowerCase(command);
michael@0 272
michael@0 273 if (!command.EqualsLiteral("ping")) {
michael@0 274 nsAutoCString desktopStartupID;
michael@0 275 nsDependentCString cmd(aCommand);
michael@0 276 FindExtensionParameterInCommand("DESKTOP_STARTUP_ID",
michael@0 277 cmd, '\n',
michael@0 278 &desktopStartupID);
michael@0 279
michael@0 280 const char* argv[3] = {"dummyappname", "-remote", aCommand};
michael@0 281 rv = cmdline->Init(3, argv, nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
michael@0 282 if (NS_FAILED(rv))
michael@0 283 return "509 internal error";
michael@0 284
michael@0 285 if (aWindow)
michael@0 286 cmdline->SetWindowContext(aWindow);
michael@0 287
michael@0 288 if (sRemoteImplementation)
michael@0 289 sRemoteImplementation->SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
michael@0 290
michael@0 291 rv = cmdline->Run();
michael@0 292 if (NS_ERROR_ABORT == rv)
michael@0 293 return "500 command not parseable";
michael@0 294 if (NS_FAILED(rv))
michael@0 295 return "509 internal error";
michael@0 296 }
michael@0 297
michael@0 298 return "200 executed command";
michael@0 299 }
michael@0 300
michael@0 301 const char*
michael@0 302 nsXRemoteService::HandleCommandLine(char* aBuffer, nsIDOMWindow* aWindow,
michael@0 303 uint32_t aTimestamp)
michael@0 304 {
michael@0 305 nsresult rv;
michael@0 306
michael@0 307 nsCOMPtr<nsICommandLineRunner> cmdline
michael@0 308 (do_CreateInstance("@mozilla.org/toolkit/command-line;1", &rv));
michael@0 309 if (NS_FAILED(rv))
michael@0 310 return "509 internal error";
michael@0 311
michael@0 312 // the commandline property is constructed as an array of int32_t
michael@0 313 // followed by a series of null-terminated strings:
michael@0 314 //
michael@0 315 // [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
michael@0 316 // (offset is from the beginning of the buffer)
michael@0 317
michael@0 318 int32_t argc = TO_LITTLE_ENDIAN32(*reinterpret_cast<int32_t*>(aBuffer));
michael@0 319 char *wd = aBuffer + ((argc + 1) * sizeof(int32_t));
michael@0 320
michael@0 321 nsCOMPtr<nsIFile> lf;
michael@0 322 rv = NS_NewNativeLocalFile(nsDependentCString(wd), true,
michael@0 323 getter_AddRefs(lf));
michael@0 324 if (NS_FAILED(rv))
michael@0 325 return "509 internal error";
michael@0 326
michael@0 327 nsAutoCString desktopStartupID;
michael@0 328
michael@0 329 char **argv = (char**) malloc(sizeof(char*) * argc);
michael@0 330 if (!argv) return "509 internal error";
michael@0 331
michael@0 332 int32_t *offset = reinterpret_cast<int32_t*>(aBuffer) + 1;
michael@0 333
michael@0 334 for (int i = 0; i < argc; ++i) {
michael@0 335 argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]);
michael@0 336
michael@0 337 if (i == 0) {
michael@0 338 nsDependentCString cmd(argv[0]);
michael@0 339 FindExtensionParameterInCommand("DESKTOP_STARTUP_ID",
michael@0 340 cmd, ' ',
michael@0 341 &desktopStartupID);
michael@0 342 }
michael@0 343 }
michael@0 344
michael@0 345 rv = cmdline->Init(argc, argv, lf, nsICommandLine::STATE_REMOTE_AUTO);
michael@0 346
michael@0 347 free (argv);
michael@0 348 if (NS_FAILED(rv)) {
michael@0 349 return "509 internal error";
michael@0 350 }
michael@0 351
michael@0 352 if (aWindow)
michael@0 353 cmdline->SetWindowContext(aWindow);
michael@0 354
michael@0 355 if (sRemoteImplementation)
michael@0 356 sRemoteImplementation->SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
michael@0 357
michael@0 358 rv = cmdline->Run();
michael@0 359
michael@0 360 if (NS_ERROR_ABORT == rv)
michael@0 361 return "500 command not parseable";
michael@0 362
michael@0 363 if (NS_FAILED(rv))
michael@0 364 return "509 internal error";
michael@0 365
michael@0 366 return "200 executed command";
michael@0 367 }
michael@0 368
michael@0 369 void
michael@0 370 nsXRemoteService::EnsureAtoms(void)
michael@0 371 {
michael@0 372 if (sMozVersionAtom)
michael@0 373 return;
michael@0 374
michael@0 375 XInternAtoms(mozilla::DefaultXDisplay(), const_cast<char**>(XAtomNames),
michael@0 376 ArrayLength(XAtomNames), False, XAtoms);
michael@0 377
michael@0 378 int i = 0;
michael@0 379 sMozVersionAtom = XAtoms[i++];
michael@0 380 sMozLockAtom = XAtoms[i++];
michael@0 381 sMozCommandAtom = XAtoms[i++];
michael@0 382 sMozResponseAtom = XAtoms[i++];
michael@0 383 sMozUserAtom = XAtoms[i++];
michael@0 384 sMozProfileAtom = XAtoms[i++];
michael@0 385 sMozProgramAtom = XAtoms[i++];
michael@0 386 sMozCommandLineAtom = XAtoms[i++];
michael@0 387 }

mercurial