LCOV - code coverage report
Current view: top level - widget/xremoteclient - XRemoteClient.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 332 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 14 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:expandtab:shiftwidth=2:tabstop=8:
       3             :  */
       4             : /* vim:set ts=8 sw=2 et cindent: */
       5             : /* This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       8             : 
       9             : #include "mozilla/ArrayUtils.h"
      10             : #include "mozilla/IntegerPrintfMacros.h"
      11             : #include "mozilla/Sprintf.h"
      12             : #include "XRemoteClient.h"
      13             : #include "plstr.h"
      14             : #include "prsystem.h"
      15             : #include "mozilla/Logging.h"
      16             : #include "prenv.h"
      17             : #include "prdtoa.h"
      18             : #include <stdlib.h>
      19             : #include <unistd.h>
      20             : #include <string.h>
      21             : #include <strings.h>
      22             : #include <sys/time.h>
      23             : #include <sys/types.h>
      24             : #include <unistd.h>
      25             : #include <limits.h>
      26             : #include <X11/Xatom.h>
      27             : 
      28             : #define MOZILLA_VERSION_PROP   "_MOZILLA_VERSION"
      29             : #define MOZILLA_LOCK_PROP      "_MOZILLA_LOCK"
      30             : #define MOZILLA_COMMANDLINE_PROP "_MOZILLA_COMMANDLINE"
      31             : #define MOZILLA_RESPONSE_PROP  "_MOZILLA_RESPONSE"
      32             : #define MOZILLA_USER_PROP      "_MOZILLA_USER"
      33             : #define MOZILLA_PROFILE_PROP   "_MOZILLA_PROFILE"
      34             : #define MOZILLA_PROGRAM_PROP   "_MOZILLA_PROGRAM"
      35             : 
      36             : #ifdef IS_BIG_ENDIAN
      37             : #define TO_LITTLE_ENDIAN32(x) \
      38             :     ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
      39             :     (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
      40             : #else
      41             : #define TO_LITTLE_ENDIAN32(x) (x)
      42             : #endif
      43             :     
      44             : #ifndef MAX_PATH
      45             : #ifdef PATH_MAX
      46             : #define MAX_PATH PATH_MAX
      47             : #else
      48             : #define MAX_PATH 1024
      49             : #endif
      50             : #endif
      51             : 
      52             : using mozilla::LogLevel;
      53             : 
      54             : static mozilla::LazyLogModule sRemoteLm("XRemoteClient");
      55             : 
      56             : static int (*sOldHandler)(Display *, XErrorEvent *);
      57             : static bool sGotBadWindow;
      58             : 
      59           0 : XRemoteClient::XRemoteClient()
      60             : {
      61           0 :   mDisplay = 0;
      62           0 :   mInitialized = false;
      63           0 :   mMozVersionAtom = 0;
      64           0 :   mMozLockAtom = 0;
      65           0 :   mMozCommandLineAtom = 0;
      66           0 :   mMozResponseAtom = 0;
      67           0 :   mMozWMStateAtom = 0;
      68           0 :   mMozUserAtom = 0;
      69           0 :   mMozProfileAtom = 0;
      70           0 :   mMozProgramAtom = 0;
      71           0 :   mLockData = 0;
      72           0 :   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::XRemoteClient"));
      73           0 : }
      74             : 
      75           0 : XRemoteClient::~XRemoteClient()
      76             : {
      77           0 :   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::~XRemoteClient"));
      78           0 :   if (mInitialized)
      79           0 :     Shutdown();
      80           0 : }
      81             : 
      82             : // Minimize the roundtrips to the X-server
      83             : static const char *XAtomNames[] = {
      84             :   MOZILLA_VERSION_PROP,
      85             :   MOZILLA_LOCK_PROP,
      86             :   MOZILLA_RESPONSE_PROP,
      87             :   "WM_STATE",
      88             :   MOZILLA_USER_PROP,
      89             :   MOZILLA_PROFILE_PROP,
      90             :   MOZILLA_PROGRAM_PROP,
      91             :   MOZILLA_COMMANDLINE_PROP
      92             : };
      93             : static Atom XAtoms[MOZ_ARRAY_LENGTH(XAtomNames)];
      94             : 
      95             : nsresult
      96           0 : XRemoteClient::Init()
      97             : {
      98           0 :   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::Init"));
      99             : 
     100           0 :   if (mInitialized)
     101           0 :     return NS_OK;
     102             : 
     103             :   // try to open the display
     104           0 :   mDisplay = XOpenDisplay(0);
     105           0 :   if (!mDisplay)
     106           0 :     return NS_ERROR_FAILURE;
     107             : 
     108             :   // get our atoms
     109           0 :   XInternAtoms(mDisplay, const_cast<char**>(XAtomNames),
     110           0 :                MOZ_ARRAY_LENGTH(XAtomNames), False, XAtoms);
     111             : 
     112           0 :   int i = 0;
     113           0 :   mMozVersionAtom  = XAtoms[i++];
     114           0 :   mMozLockAtom     = XAtoms[i++];
     115           0 :   mMozResponseAtom = XAtoms[i++];
     116           0 :   mMozWMStateAtom  = XAtoms[i++];
     117           0 :   mMozUserAtom     = XAtoms[i++];
     118           0 :   mMozProfileAtom  = XAtoms[i++];
     119           0 :   mMozProgramAtom  = XAtoms[i++];
     120           0 :   mMozCommandLineAtom = XAtoms[i++];
     121             : 
     122           0 :   mInitialized = true;
     123             : 
     124           0 :   return NS_OK;
     125             : }
     126             : 
     127             : void
     128           0 : XRemoteClient::Shutdown (void)
     129             : {
     130           0 :   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::Shutdown"));
     131             : 
     132           0 :   if (!mInitialized)
     133           0 :     return;
     134             : 
     135             :   // shut everything down
     136           0 :   XCloseDisplay(mDisplay);
     137           0 :   mDisplay = 0;
     138           0 :   mInitialized = false;
     139           0 :   if (mLockData) {
     140           0 :     free(mLockData);
     141           0 :     mLockData = 0;
     142             :   }
     143             : }
     144             : 
     145             : static int
     146           0 : HandleBadWindow(Display *display, XErrorEvent *event)
     147             : {
     148           0 :   if (event->error_code == BadWindow) {
     149           0 :     sGotBadWindow = true;
     150           0 :     return 0; // ignored
     151             :   }
     152             :   
     153           0 :     return (*sOldHandler)(display, event);
     154             :   
     155             : }
     156             : 
     157             : nsresult
     158           0 : XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
     159             :                                 const char *aProfile,
     160             :                                 int32_t argc, char **argv,
     161             :                                 const char* aDesktopStartupID,
     162             :                                 char **aResponse, bool *aWindowFound)
     163             : {
     164           0 :   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::SendCommandLine"));
     165             : 
     166           0 :   *aWindowFound = false;
     167             : 
     168             :   // FindBestWindow() iterates down the window hierarchy, so catch X errors
     169             :   // when windows get destroyed before being accessed.
     170           0 :   sOldHandler = XSetErrorHandler(HandleBadWindow);
     171             : 
     172           0 :   Window w = FindBestWindow(aProgram, aUsername, aProfile);
     173             : 
     174           0 :   nsresult rv = NS_OK;
     175             : 
     176           0 :   if (w) {
     177             :     // ok, let the caller know that we at least found a window.
     178           0 :     *aWindowFound = true;
     179             : 
     180             :     // Ignore BadWindow errors up to this point.  The last request from
     181             :     // FindBestWindow() was a synchronous XGetWindowProperty(), so no need to
     182             :     // Sync.  Leave the error handler installed to detect if w gets destroyed.
     183           0 :     sGotBadWindow = false;
     184             : 
     185             :     // make sure we get the right events on that window
     186           0 :     XSelectInput(mDisplay, w,
     187           0 :                  (PropertyChangeMask|StructureNotifyMask));
     188             : 
     189           0 :     bool destroyed = false;
     190             : 
     191             :     // get the lock on the window
     192           0 :     rv = GetLock(w, &destroyed);
     193             : 
     194           0 :     if (NS_SUCCEEDED(rv)) {
     195             :       // send our command
     196             :       rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse,
     197           0 :                              &destroyed);
     198             : 
     199             :       // if the window was destroyed, don't bother trying to free the
     200             :       // lock.
     201           0 :       if (!destroyed)
     202           0 :           FreeLock(w); // doesn't really matter what this returns
     203             : 
     204             :     }
     205             :   }
     206             : 
     207           0 :   XSetErrorHandler(sOldHandler);
     208             : 
     209           0 :   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("SendCommandInternal returning 0x%" PRIx32 "\n",
     210             :                                        static_cast<uint32_t>(rv)));
     211             : 
     212           0 :   return rv;
     213             : }
     214             : 
     215             : Window
     216           0 : XRemoteClient::CheckWindow(Window aWindow)
     217             : {
     218           0 :   Atom type = None;
     219             :   int  format;
     220             :   unsigned long nitems, bytesafter;
     221             :   unsigned char *data;
     222             :   Window innerWindow;
     223             : 
     224           0 :   XGetWindowProperty(mDisplay, aWindow, mMozWMStateAtom,
     225             :                      0, 0, False, AnyPropertyType,
     226           0 :                      &type, &format, &nitems, &bytesafter, &data);
     227             : 
     228           0 :   if (type) {
     229           0 :     XFree(data);
     230           0 :     return aWindow;
     231             :   }
     232             : 
     233             :   // didn't find it here so check the children of this window
     234           0 :   innerWindow = CheckChildren(aWindow);
     235             : 
     236           0 :   if (innerWindow)
     237           0 :     return innerWindow;
     238             : 
     239           0 :   return aWindow;
     240             : }
     241             : 
     242             : Window
     243           0 : XRemoteClient::CheckChildren(Window aWindow)
     244             : {
     245             :   Window root, parent;
     246             :   Window *children;
     247             :   unsigned int nchildren;
     248             :   unsigned int i;
     249           0 :   Atom type = None;
     250             :   int format;
     251             :   unsigned long nitems, after;
     252             :   unsigned char *data;
     253           0 :   Window retval = None;
     254             :   
     255           0 :   if (!XQueryTree(mDisplay, aWindow, &root, &parent, &children,
     256             :                   &nchildren))
     257           0 :     return None;
     258             :   
     259             :   // scan the list first before recursing into the list of windows
     260             :   // which can get quite deep.
     261           0 :   for (i=0; !retval && (i < nchildren); i++) {
     262           0 :     XGetWindowProperty(mDisplay, children[i], mMozWMStateAtom,
     263             :                        0, 0, False, AnyPropertyType, &type, &format,
     264           0 :                        &nitems, &after, &data);
     265           0 :     if (type) {
     266           0 :       XFree(data);
     267           0 :       retval = children[i];
     268             :     }
     269             :   }
     270             : 
     271             :   // otherwise recurse into the list
     272           0 :   for (i=0; !retval && (i < nchildren); i++) {
     273           0 :     retval = CheckChildren(children[i]);
     274             :   }
     275             : 
     276           0 :   if (children)
     277           0 :     XFree((char *)children);
     278             : 
     279           0 :   return retval;
     280             : }
     281             : 
     282             : nsresult
     283           0 : XRemoteClient::GetLock(Window aWindow, bool *aDestroyed)
     284             : {
     285           0 :   bool locked = false;
     286           0 :   bool waited = false;
     287           0 :   *aDestroyed = false;
     288             : 
     289           0 :   nsresult rv = NS_OK;
     290             : 
     291           0 :   if (!mLockData) {
     292             :     
     293             :     char pidstr[32];
     294             :     char sysinfobuf[SYS_INFO_BUFFER_LENGTH];
     295           0 :     SprintfLiteral(pidstr, "pid%d@", getpid());
     296             :     PRStatus status;
     297             :     status = PR_GetSystemInfo(PR_SI_HOSTNAME, sysinfobuf,
     298           0 :                               SYS_INFO_BUFFER_LENGTH);
     299           0 :     if (status != PR_SUCCESS) {
     300           0 :       return NS_ERROR_FAILURE;
     301             :     }
     302             :     
     303             :     // allocate enough space for the string plus the terminating
     304             :     // char
     305           0 :     mLockData = (char *)malloc(strlen(pidstr) + strlen(sysinfobuf) + 1);
     306           0 :     if (!mLockData)
     307           0 :       return NS_ERROR_OUT_OF_MEMORY;
     308             : 
     309           0 :     strcpy(mLockData, pidstr);
     310           0 :     if (!strcat(mLockData, sysinfobuf))
     311           0 :       return NS_ERROR_FAILURE;
     312             :   }
     313             : 
     314           0 :   do {
     315             :     int result;
     316             :     Atom actual_type;
     317             :     int actual_format;
     318             :     unsigned long nitems, bytes_after;
     319           0 :     unsigned char *data = 0;
     320             : 
     321           0 :     XGrabServer(mDisplay);
     322             : 
     323           0 :     result = XGetWindowProperty (mDisplay, aWindow, mMozLockAtom,
     324             :                                  0, (65536 / sizeof (long)),
     325             :                                  False, /* don't delete */
     326             :                                  XA_STRING,
     327             :                                  &actual_type, &actual_format,
     328             :                                  &nitems, &bytes_after,
     329           0 :                                  &data);
     330             : 
     331             :     // aWindow may have been destroyed before XSelectInput was processed, in
     332             :     // which case there may not be any DestroyNotify event in the queue to
     333             :     // tell us.  XGetWindowProperty() was synchronous so error responses have
     334             :     // now been processed, setting sGotBadWindow.
     335           0 :     if (sGotBadWindow) {
     336           0 :       *aDestroyed = true;
     337           0 :       rv = NS_ERROR_FAILURE;
     338             :     }
     339           0 :     else if (result != Success || actual_type == None) {
     340             :       /* It's not now locked - lock it. */
     341           0 :       XChangeProperty (mDisplay, aWindow, mMozLockAtom, XA_STRING, 8,
     342             :                        PropModeReplace,
     343           0 :                        (unsigned char *)mLockData,
     344           0 :                        strlen(mLockData));
     345           0 :       locked = True;
     346             :     }
     347             : 
     348           0 :     XUngrabServer(mDisplay);
     349           0 :     XFlush(mDisplay); // ungrab now!
     350             : 
     351           0 :     if (!locked && !NS_FAILED(rv)) {
     352             :       /* We tried to grab the lock this time, and failed because someone
     353             :          else is holding it already.  So, wait for a PropertyDelete event
     354             :          to come in, and try again. */
     355           0 :       MOZ_LOG(sRemoteLm, LogLevel::Debug, 
     356             :              ("window 0x%x is locked by %s; waiting...\n",
     357             :               (unsigned int) aWindow, data));
     358           0 :       waited = True;
     359             :       while (true) {
     360             :         XEvent event;
     361             :         int select_retval;
     362             :         fd_set select_set;
     363             :         struct timeval delay;
     364           0 :         delay.tv_sec = 10;
     365           0 :         delay.tv_usec = 0;
     366             : 
     367           0 :         FD_ZERO(&select_set);
     368             :         // add the x event queue to the select set
     369           0 :         FD_SET(ConnectionNumber(mDisplay), &select_set);
     370           0 :         select_retval = select(ConnectionNumber(mDisplay) + 1,
     371           0 :                                &select_set, nullptr, nullptr, &delay);
     372             :         // did we time out?
     373           0 :         if (select_retval == 0) {
     374           0 :           MOZ_LOG(sRemoteLm, LogLevel::Debug, ("timed out waiting for window\n"));
     375           0 :           rv = NS_ERROR_FAILURE;
     376           0 :           break;
     377             :         }
     378           0 :         MOZ_LOG(sRemoteLm, LogLevel::Debug, ("xevent...\n"));
     379           0 :         XNextEvent (mDisplay, &event);
     380           0 :         if (event.xany.type == DestroyNotify &&
     381           0 :             event.xdestroywindow.window == aWindow) {
     382           0 :           *aDestroyed = true;
     383           0 :           rv = NS_ERROR_FAILURE;
     384           0 :           break;
     385             :         }
     386           0 :         if (event.xany.type == PropertyNotify &&
     387           0 :                  event.xproperty.state == PropertyDelete &&
     388           0 :                  event.xproperty.window == aWindow &&
     389           0 :                  event.xproperty.atom == mMozLockAtom) {
     390             :           /* Ok!  Someone deleted their lock, so now we can try
     391             :              again. */
     392           0 :           MOZ_LOG(sRemoteLm, LogLevel::Debug,
     393             :                  ("(0x%x unlocked, trying again...)\n",
     394             :                   (unsigned int) aWindow));
     395           0 :                   break;
     396             :         }
     397           0 :       }
     398             :     }
     399           0 :     if (data)
     400           0 :       XFree(data);
     401           0 :   } while (!locked && !NS_FAILED(rv));
     402             : 
     403           0 :   if (waited && locked) {
     404           0 :     MOZ_LOG(sRemoteLm, LogLevel::Debug, ("obtained lock.\n"));
     405           0 :   } else if (*aDestroyed) {
     406           0 :     MOZ_LOG(sRemoteLm, LogLevel::Debug,
     407             :            ("window 0x%x unexpectedly destroyed.\n",
     408             :             (unsigned int) aWindow));
     409             :   }
     410             : 
     411           0 :   return rv;
     412             : }
     413             : 
     414             : Window
     415           0 : XRemoteClient::FindBestWindow(const char *aProgram, const char *aUsername,
     416             :                               const char *aProfile)
     417             : {
     418           0 :   Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mDisplay));
     419           0 :   Window bestWindow = 0;
     420             :   Window root2, parent, *kids;
     421             :   unsigned int nkids;
     422             : 
     423             :   // Get a list of the children of the root window, walk the list
     424             :   // looking for the best window that fits the criteria.
     425           0 :   if (!XQueryTree(mDisplay, root, &root2, &parent, &kids, &nkids)) {
     426           0 :     MOZ_LOG(sRemoteLm, LogLevel::Debug,
     427             :            ("XQueryTree failed in XRemoteClient::FindBestWindow"));
     428           0 :     return 0;
     429             :   }
     430             : 
     431           0 :   if (!(kids && nkids)) {
     432           0 :     MOZ_LOG(sRemoteLm, LogLevel::Debug, ("root window has no children"));
     433           0 :     return 0;
     434             :   }
     435             : 
     436             :   // We'll walk the list of windows looking for a window that best
     437             :   // fits the criteria here.
     438             : 
     439           0 :   for (unsigned int i = 0; i < nkids; i++) {
     440             :     Atom type;
     441             :     int format;
     442             :     unsigned long nitems, bytesafter;
     443           0 :     unsigned char *data_return = 0;
     444             :     Window w;
     445           0 :     w = kids[i];
     446             :     // find the inner window with WM_STATE on it
     447           0 :     w = CheckWindow(w);
     448             : 
     449           0 :     int status = XGetWindowProperty(mDisplay, w, mMozVersionAtom,
     450             :                                     0, (65536 / sizeof (long)),
     451             :                                     False, XA_STRING,
     452             :                                     &type, &format, &nitems, &bytesafter,
     453           0 :                                     &data_return);
     454             : 
     455           0 :     if (!data_return)
     456           0 :       continue;
     457             : 
     458           0 :     double version = PR_strtod((char*) data_return, nullptr);
     459           0 :     XFree(data_return);
     460             : 
     461           0 :     if (!(version >= 5.1 && version < 6))
     462           0 :       continue;
     463             : 
     464           0 :     data_return = 0;
     465             : 
     466           0 :     if (status != Success || type == None)
     467           0 :       continue;
     468             : 
     469             :     // If someone passed in a program name, check it against this one
     470             :     // unless it's "any" in which case, we don't care.  If someone did
     471             :     // pass in a program name and this window doesn't support that
     472             :     // protocol, we don't include it in our list.
     473           0 :     if (aProgram && strcmp(aProgram, "any")) {
     474           0 :         status = XGetWindowProperty(mDisplay, w, mMozProgramAtom,
     475             :                                     0, (65536 / sizeof(long)),
     476             :                                     False, XA_STRING,
     477             :                                     &type, &format, &nitems, &bytesafter,
     478           0 :                                     &data_return);
     479             :         
     480             :         // If the return name is not the same as what someone passed in,
     481             :         // we don't want this window.
     482           0 :         if (data_return) {
     483           0 :             if (strcmp(aProgram, (const char *)data_return)) {
     484           0 :                 XFree(data_return);
     485           0 :                 continue;
     486             :             }
     487             : 
     488             :             // This is actually the success condition.
     489           0 :             XFree(data_return);
     490             :         }
     491             :         else {
     492             :             // Doesn't support the protocol, even though the user
     493             :             // requested it.  So we're not going to use this window.
     494           0 :             continue;
     495             :         }
     496             :     }
     497             : 
     498             :     // Check to see if it has the user atom on that window.  If there
     499             :     // is then we need to make sure that it matches what we have.
     500             :     const char *username;
     501           0 :     if (aUsername) {
     502           0 :       username = aUsername;
     503             :     }
     504             :     else {
     505           0 :       username = PR_GetEnv("LOGNAME");
     506             :     }
     507             : 
     508           0 :     if (username) {
     509           0 :         status = XGetWindowProperty(mDisplay, w, mMozUserAtom,
     510             :                                     0, (65536 / sizeof(long)),
     511             :                                     False, XA_STRING,
     512             :                                     &type, &format, &nitems, &bytesafter,
     513           0 :                                     &data_return);
     514             : 
     515             :         // if there's a username compare it with what we have
     516           0 :         if (data_return) {
     517             :             // If the IDs aren't equal, we don't want this window.
     518           0 :             if (strcmp(username, (const char *)data_return)) {
     519           0 :                 XFree(data_return);
     520           0 :                 continue;
     521             :             }
     522             : 
     523           0 :             XFree(data_return);
     524             :         }
     525             :     }
     526             : 
     527             :     // Check to see if there's a profile name on this window.  If
     528             :     // there is, then we need to make sure it matches what someone
     529             :     // passed in.
     530           0 :     if (aProfile) {
     531           0 :         status = XGetWindowProperty(mDisplay, w, mMozProfileAtom,
     532             :                                     0, (65536 / sizeof(long)),
     533             :                                     False, XA_STRING,
     534             :                                     &type, &format, &nitems, &bytesafter,
     535           0 :                                     &data_return);
     536             : 
     537             :         // If there's a profile compare it with what we have
     538           0 :         if (data_return) {
     539             :             // If the profiles aren't equal, we don't want this window.
     540           0 :             if (strcmp(aProfile, (const char *)data_return)) {
     541           0 :                 XFree(data_return);
     542           0 :                 continue;
     543             :             }
     544             : 
     545           0 :             XFree(data_return);
     546             :         }
     547             :     }
     548             : 
     549             :     // Check to see if the window supports the new command-line passing
     550             :     // protocol, if that is requested.
     551             : 
     552             :     // If we got this far, this is the best window.  It passed
     553             :     // all the tests.
     554           0 :     bestWindow = w;
     555           0 :     break;
     556             :   }
     557             : 
     558           0 :   if (kids)
     559           0 :     XFree((char *) kids);
     560             : 
     561           0 :   return bestWindow;
     562             : }
     563             : 
     564             : nsresult
     565           0 : XRemoteClient::FreeLock(Window aWindow)
     566             : {
     567             :   int result;
     568             :   Atom actual_type;
     569             :   int actual_format;
     570             :   unsigned long nitems, bytes_after;
     571           0 :   unsigned char *data = 0;
     572             : 
     573           0 :   result = XGetWindowProperty(mDisplay, aWindow, mMozLockAtom,
     574             :                               0, (65536 / sizeof(long)),
     575             :                               True, /* atomic delete after */
     576             :                               XA_STRING,
     577             :                               &actual_type, &actual_format,
     578             :                               &nitems, &bytes_after,
     579           0 :                               &data);
     580           0 :   if (result != Success) {
     581           0 :       MOZ_LOG(sRemoteLm, LogLevel::Debug,
     582             :              ("unable to read and delete " MOZILLA_LOCK_PROP
     583             :               " property\n"));
     584           0 :       return NS_ERROR_FAILURE;
     585             :   }
     586           0 :   if (!data || !*data){
     587           0 :       MOZ_LOG(sRemoteLm, LogLevel::Debug,
     588             :              ("invalid data on " MOZILLA_LOCK_PROP
     589             :               " of window 0x%x.\n",
     590             :               (unsigned int) aWindow));
     591           0 :       return NS_ERROR_FAILURE;
     592             :   }
     593           0 :   else if (strcmp((char *)data, mLockData)) {
     594           0 :       MOZ_LOG(sRemoteLm, LogLevel::Debug,
     595             :              (MOZILLA_LOCK_PROP " was stolen!  Expected \"%s\", saw \"%s\"!\n",
     596             :               mLockData, data));
     597           0 :       return NS_ERROR_FAILURE;
     598             :   }
     599             : 
     600           0 :   if (data)
     601           0 :       XFree(data);
     602           0 :   return NS_OK;
     603             : }
     604             : 
     605             : /* like strcpy, but return the char after the final null */
     606             : static char*
     607           0 : estrcpy(const char* s, char* d)
     608             : {
     609           0 :   while (*s)
     610           0 :     *d++ = *s++;
     611             : 
     612           0 :   *d++ = '\0';
     613           0 :   return d;
     614             : }
     615             : 
     616             : nsresult
     617           0 : XRemoteClient::DoSendCommandLine(Window aWindow, int32_t argc, char **argv,
     618             :                                  const char* aDesktopStartupID,
     619             :                                  char **aResponse, bool *aDestroyed)
     620             : {
     621           0 :   *aDestroyed = false;
     622             : 
     623             :   char cwdbuf[MAX_PATH];
     624           0 :   if (!getcwd(cwdbuf, MAX_PATH))
     625           0 :     return NS_ERROR_UNEXPECTED;
     626             : 
     627             :   // the commandline property is constructed as an array of int32_t
     628             :   // followed by a series of null-terminated strings:
     629             :   //
     630             :   // [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
     631             :   // (offset is from the beginning of the buffer)
     632             : 
     633             :   static char desktopStartupPrefix[] = " DESKTOP_STARTUP_ID=";
     634             : 
     635           0 :   int32_t argvlen = strlen(cwdbuf);
     636           0 :   for (int i = 0; i < argc; ++i) {
     637           0 :     int32_t len = strlen(argv[i]);
     638           0 :     if (i == 0 && aDesktopStartupID) {
     639           0 :       len += sizeof(desktopStartupPrefix) - 1 + strlen(aDesktopStartupID);
     640             :     }
     641           0 :     argvlen += len;
     642             :   }
     643             : 
     644           0 :   auto* buffer = (int32_t*) malloc(argvlen + argc + 1 +
     645           0 :                                       sizeof(int32_t) * (argc + 1));
     646           0 :   if (!buffer)
     647           0 :     return NS_ERROR_OUT_OF_MEMORY;
     648             : 
     649           0 :   buffer[0] = TO_LITTLE_ENDIAN32(argc);
     650             : 
     651           0 :   auto *bufend = (char*) (buffer + argc + 1);
     652             : 
     653           0 :   bufend = estrcpy(cwdbuf, bufend);
     654             : 
     655           0 :   for (int i = 0; i < argc; ++i) {
     656           0 :     buffer[i + 1] = TO_LITTLE_ENDIAN32(bufend - ((char*) buffer));
     657           0 :     bufend = estrcpy(argv[i], bufend);
     658           0 :     if (i == 0 && aDesktopStartupID) {
     659           0 :       bufend = estrcpy(desktopStartupPrefix, bufend - 1);
     660           0 :       bufend = estrcpy(aDesktopStartupID, bufend - 1);
     661             :     }
     662             :   }
     663             : 
     664             : #ifdef DEBUG_bsmedberg
     665             :   int32_t   debug_argc   = TO_LITTLE_ENDIAN32(*buffer);
     666             :   char *debug_workingdir = (char*) (buffer + argc + 1);
     667             : 
     668             :   printf("Sending command line:\n"
     669             :          "  working dir: %s\n"
     670             :          "  argc:\t%i",
     671             :          debug_workingdir,
     672             :          debug_argc);
     673             : 
     674             :   int32_t  *debug_offset = buffer + 1;
     675             :   for (int debug_i = 0; debug_i < debug_argc; ++debug_i)
     676             :     printf("  argv[%i]:\t%s\n", debug_i,
     677             :            ((char*) buffer) + TO_LITTLE_ENDIAN32(debug_offset[debug_i]));
     678             : #endif
     679             : 
     680           0 :   XChangeProperty (mDisplay, aWindow, mMozCommandLineAtom, XA_STRING, 8,
     681             :                    PropModeReplace, (unsigned char *) buffer,
     682           0 :                    bufend - ((char*) buffer));
     683           0 :   free(buffer);
     684             : 
     685           0 :   if (!WaitForResponse(aWindow, aResponse, aDestroyed, mMozCommandLineAtom))
     686           0 :     return NS_ERROR_FAILURE;
     687             :   
     688           0 :   return NS_OK;
     689             : }
     690             : 
     691             : bool
     692           0 : XRemoteClient::WaitForResponse(Window aWindow, char **aResponse,
     693             :                                bool *aDestroyed, Atom aCommandAtom)
     694             : {
     695           0 :   bool done = false;
     696           0 :   bool accepted = false;
     697             : 
     698           0 :   while (!done) {
     699             :     XEvent event;
     700           0 :     XNextEvent (mDisplay, &event);
     701           0 :     if (event.xany.type == DestroyNotify &&
     702           0 :         event.xdestroywindow.window == aWindow) {
     703             :       /* Print to warn user...*/
     704           0 :       MOZ_LOG(sRemoteLm, LogLevel::Debug,
     705             :              ("window 0x%x was destroyed.\n",
     706             :               (unsigned int) aWindow));
     707           0 :       *aResponse = strdup("Window was destroyed while reading response.");
     708           0 :       *aDestroyed = true;
     709           0 :       return false;
     710             :     }
     711           0 :     if (event.xany.type == PropertyNotify &&
     712           0 :              event.xproperty.state == PropertyNewValue &&
     713           0 :              event.xproperty.window == aWindow &&
     714           0 :              event.xproperty.atom == mMozResponseAtom) {
     715             :       Atom actual_type;
     716             :       int actual_format;
     717             :       unsigned long nitems, bytes_after;
     718           0 :       unsigned char *data = 0;
     719             :       Bool result;
     720           0 :       result = XGetWindowProperty (mDisplay, aWindow, mMozResponseAtom,
     721             :                                    0, (65536 / sizeof (long)),
     722             :                                    True, /* atomic delete after */
     723             :                                    XA_STRING,
     724             :                                    &actual_type, &actual_format,
     725             :                                    &nitems, &bytes_after,
     726           0 :                                    &data);
     727           0 :       if (result != Success) {
     728           0 :         MOZ_LOG(sRemoteLm, LogLevel::Debug,
     729             :                ("failed reading " MOZILLA_RESPONSE_PROP
     730             :                 " from window 0x%0x.\n",
     731             :                 (unsigned int) aWindow));
     732           0 :         *aResponse = strdup("Internal error reading response from window.");
     733           0 :         done = true;
     734             :       }
     735           0 :       else if (!data || strlen((char *) data) < 5) {
     736           0 :         MOZ_LOG(sRemoteLm, LogLevel::Debug,
     737             :                ("invalid data on " MOZILLA_RESPONSE_PROP
     738             :                 " property of window 0x%0x.\n",
     739             :                 (unsigned int) aWindow));
     740           0 :         *aResponse = strdup("Server returned invalid data in response.");
     741           0 :         done = true;
     742             :       }
     743           0 :       else if (*data == '1') {  /* positive preliminary reply */
     744           0 :         MOZ_LOG(sRemoteLm, LogLevel::Debug,  ("%s\n", data + 4));
     745             :         /* keep going */
     746           0 :         done = false;
     747             :       }
     748             : 
     749           0 :       else if (!strncmp ((char *)data, "200", 3)) { /* positive completion */
     750           0 :         *aResponse = strdup((char *)data);
     751           0 :         accepted = true;
     752           0 :         done = true;
     753             :       }
     754             : 
     755           0 :       else if (*data == '2') {  /* positive completion */
     756           0 :         MOZ_LOG(sRemoteLm, LogLevel::Debug, ("%s\n", data + 4));
     757           0 :         *aResponse = strdup((char *)data);
     758           0 :         accepted = true;
     759           0 :         done = true;
     760             :       }
     761             : 
     762           0 :       else if (*data == '3') {  /* positive intermediate reply */
     763           0 :         MOZ_LOG(sRemoteLm, LogLevel::Debug,
     764             :                ("internal error: "
     765             :                 "server wants more information?  (%s)\n",
     766             :                 data));
     767           0 :         *aResponse = strdup((char *)data);
     768           0 :         done = true;
     769             :       }
     770             : 
     771           0 :       else if (*data == '4' ||  /* transient negative completion */
     772           0 :                *data == '5') {  /* permanent negative completion */
     773           0 :         MOZ_LOG(sRemoteLm, LogLevel::Debug, ("%s\n", data + 4));
     774           0 :         *aResponse = strdup((char *)data);
     775           0 :         done = true;
     776             :       }
     777             : 
     778             :       else {
     779           0 :         MOZ_LOG(sRemoteLm, LogLevel::Debug,
     780             :                ("unrecognised " MOZILLA_RESPONSE_PROP
     781             :                 " from window 0x%x: %s\n",
     782             :                 (unsigned int) aWindow, data));
     783           0 :         *aResponse = strdup((char *)data);
     784           0 :         done = true;
     785             :       }
     786             : 
     787           0 :       if (data)
     788           0 :         XFree(data);
     789             :     }
     790             : 
     791           0 :     else if (event.xany.type == PropertyNotify &&
     792           0 :              event.xproperty.window == aWindow &&
     793           0 :              event.xproperty.state == PropertyDelete &&
     794           0 :              event.xproperty.atom == aCommandAtom) {
     795           0 :       MOZ_LOG(sRemoteLm, LogLevel::Debug,
     796             :              ("(server 0x%x has accepted "
     797             :               MOZILLA_COMMANDLINE_PROP ".)\n",
     798             :               (unsigned int) aWindow));
     799             :     }
     800             :     
     801             :   }
     802             : 
     803           0 :   return accepted;
     804             : }

Generated by: LCOV version 1.13