LCOV - code coverage report
Current view: directory - widget/xremoteclient - XRemoteClient.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 333 0 0.0 %
Date: 2012-06-02 Functions: 17 0 0.0 %

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

Generated by: LCOV version 1.7