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.

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

mercurial