/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 | } |