Coverage Report

Created: 2018-09-25 14:53

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