/usr/lib/python2.7/dist-packages/xpra/client/gobject_client_base.py is in xpra 0.17.6+dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | # This file is part of Xpra.
# Copyright (C) 2010-2015 Antoine Martin <antoine@devloop.org.uk>
# Copyright (C) 2008, 2010 Nathaniel Smith <njs@pobox.com>
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.
from xpra.gtk_common.gobject_compat import import_gobject, import_glib
gobject = import_gobject()
glib = import_glib()
from xpra.log import Logger
log = Logger("gobject", "client")
import os
import sys
from xpra.util import nonl, sorted_nicely, print_nested_dict, DONE
from xpra.os_util import bytestostr
from xpra.client.client_base import XpraClientBase, EXTRA_TIMEOUT, \
EXIT_TIMEOUT, EXIT_OK, EXIT_UNSUPPORTED, EXIT_REMOTE_ERROR, EXIT_FILE_TOO_BIG
FLATTEN_INFO = int(os.environ.get("XPRA_FLATTEN_INFO", "1"))
class GObjectXpraClient(XpraClientBase, gobject.GObject):
"""
Utility superclass for GObject clients
"""
def __init__(self):
gobject.GObject.__init__(self)
XpraClientBase.__init__(self)
def init(self, opts):
XpraClientBase.init(self, opts)
self.install_signal_handlers()
self.glib_init()
self.gobject_init()
def timeout_add(self, *args):
return glib.timeout_add(*args)
def idle_add(self, *args):
return glib.idle_add(*args)
def source_remove(self, *args):
return glib.source_remove(*args)
def get_scheduler(self):
return glib
def client_type(self):
#overriden in subclasses!
return "Python%s/GObject" % sys.version_info[0]
def timeout(self, *args):
log.warn("timeout!")
def init_packet_handlers(self):
XpraClientBase.init_packet_handlers(self)
def noop(*args):
log("ignoring packet: %s", args)
#ignore the following packet types without error:
#(newer servers should avoid sending us any of those)
for t in ["new-window", "new-override-redirect",
"draw", "cursor", "bell",
"notify_show", "notify_close",
"ping", "ping_echo",
"window-metadata", "configure-override-redirect",
"lost-window"]:
self._packet_handlers[t] = noop
def gobject_init(self):
try:
gobject.threads_init()
except AttributeError:
#old versions of gobject may not have this method
pass
def connect_with_timeout(self, conn):
self.setup_connection(conn)
if conn.timeout>0:
glib.timeout_add((conn.timeout + EXTRA_TIMEOUT) * 1000, self.timeout)
glib.idle_add(self.send_hello)
def run(self):
XpraClientBase.run(self)
self.glib_mainloop = glib.MainLoop()
self.glib_mainloop.run()
return self.exit_code
def make_hello(self):
capabilities = XpraClientBase.make_hello(self)
capabilities["keyboard"] = False
return capabilities
def quit(self, exit_code):
log("quit(%s) current exit_code=%s", exit_code, self.exit_code)
if self.exit_code is None:
self.exit_code = exit_code
self.cleanup()
glib.timeout_add(50, self.glib_mainloop.quit)
class CommandConnectClient(GObjectXpraClient):
"""
Utility superclass for clients that only send one command
via the hello packet.
"""
def __init__(self, conn, opts):
GObjectXpraClient.__init__(self)
GObjectXpraClient.init(self, opts)
self.connect_with_timeout(conn)
self._protocol._log_stats = False
#not used by command line clients,
#so don't try probing for printers, etc
self.file_transfer = False
self.printing = False
def make_hello(self):
capabilities = GObjectXpraClient.make_hello(self)
#don't bother with many of these things for one-off commands:
for x in ("ui_client", "wants_aliases", "wants_encodings",
"wants_versions", "wants_features", "wants_sound", "windows"):
capabilities[x] = False
return capabilities
def _process_connection_lost(self, packet):
#override so we don't log a warning
#"command clients" are meant to exit quickly by losing the connection
self.quit(EXIT_OK)
def server_connection_established(self):
#don't bother parsing the network caps:
#* it could cause errors if the caps are missing
#* we don't care about sending anything back after hello
log("server_capabilities: %s", self.server_capabilities)
log("protocol state: %s", self._protocol.save_state())
self.do_command()
def do_command(self):
raise NotImplementedError()
class SendCommandConnectClient(CommandConnectClient):
"""
Utility superclass for clients that only send at least one more packet
after the hello packet.
So unlike CommandConnectClient, we do need the network and encryption to be setup.
"""
def server_connection_established(self):
assert self.parse_encryption_capabilities(), "encryption failure"
assert self.parse_network_capabilities(), "network capabilities failure"
CommandConnectClient.server_connection_established(self)
class ScreenshotXpraClient(CommandConnectClient):
""" This client does one thing only:
it sends the hello packet with a screenshot request
and exits when the resulting image is received (or timedout)
"""
def __init__(self, conn, opts, screenshot_filename):
self.screenshot_filename = screenshot_filename
CommandConnectClient.__init__(self, conn, opts)
def timeout(self, *args):
self.warn_and_quit(EXIT_TIMEOUT, "timeout: did not receive the screenshot")
def _process_screenshot(self, packet):
(w, h, encoding, _, img_data) = packet[1:6]
assert encoding=="png"
if len(img_data)==0:
self.warn_and_quit(EXIT_OK, "screenshot is empty and has not been saved (maybe there are no windows or they are not currently shown)")
return
with open(self.screenshot_filename, 'wb') as f:
f.write(img_data)
self.warn_and_quit(EXIT_OK, "screenshot %sx%s saved to: %s" % (w, h, self.screenshot_filename))
def init_packet_handlers(self):
GObjectXpraClient.init_packet_handlers(self)
self._ui_packet_handlers["screenshot"] = self._process_screenshot
def make_hello(self):
capabilities = GObjectXpraClient.make_hello(self)
capabilities["screenshot_request"] = True
return capabilities
class InfoXpraClient(CommandConnectClient):
""" This client does one thing only:
it queries the server with an 'info' request
"""
def timeout(self, *args):
self.warn_and_quit(EXIT_TIMEOUT, "timeout: did not receive the info")
def do_command(self):
if self.server_capabilities:
if FLATTEN_INFO<2:
#compatibility mode:
for k in sorted_nicely(self.server_capabilities.keys()):
v = self.server_capabilities.get(k)
if sys.version_info[0]>=3:
#FIXME: this is a nasty and horrible python3 workaround (yet again)
#we want to print bytes as strings without the ugly 'b' prefix..
#it assumes that all the strings are raw or in (possibly nested) lists or tuples only
def fixvalue(w):
if type(w)==bytes:
return bytestostr(w)
elif type(w) in (tuple,list):
return type(w)([fixvalue(x) for x in w])
return w
v = fixvalue(v)
log.info("%s=%s", bytestostr(k), nonl(v))
else:
print_nested_dict(self.server_capabilities)
self.quit(EXIT_OK)
def make_hello(self):
capabilities = GObjectXpraClient.make_hello(self)
log("make_hello() adding info_request to %s", capabilities)
capabilities["info_request"] = True
if FLATTEN_INFO!=1:
capabilities["info-namespace"] = True
return capabilities
class MonitorXpraClient(SendCommandConnectClient):
""" This client does one thing only:
it prints out events received from the server.
If the server does not support this feature it exits with an error.
"""
def timeout(self, *args):
pass
#self.warn_and_quit(EXIT_TIMEOUT, "timeout: did not receive the info")
def do_command(self):
log.info("waiting for server events")
def _process_server_event(self, packet):
log.info(": ".join(packet[1:]))
def init_packet_handlers(self):
SendCommandConnectClient.init_packet_handlers(self)
self._packet_handlers["server-event"] = self._process_server_event
self._packet_handlers["ping"] = self._process_ping
def make_hello(self):
capabilities = SendCommandConnectClient.make_hello(self)
log("make_hello() adding info_request to %s", capabilities)
capabilities["wants_features"] = True #so we can verify that the server supports monitor mode
capabilities["wants_events"] = True #tell the server we do support server events
capabilities["event_request"] = True #ask the server to enter this request mode (we're not a proper client)
return capabilities
def _process_ping(self, packet):
echotime = packet[1]
self.send("ping_echo", echotime, 0, 0, 0, -1)
class VersionXpraClient(CommandConnectClient):
""" This client does one thing only:
it queries the server for version information and prints it out
"""
def timeout(self, *args):
self.warn_and_quit(EXIT_TIMEOUT, "timeout: did not receive the version")
def do_command(self):
self.warn_and_quit(EXIT_OK, str(self.server_capabilities.get("version")))
def make_hello(self):
capabilities = GObjectXpraClient.make_hello(self)
log("make_hello() adding version_request to %s", capabilities)
capabilities["version_request"] = True
return capabilities
class ControlXpraClient(CommandConnectClient):
""" Allows us to send commands to a server.
"""
def set_command_args(self, command):
self.command = command
def timeout(self, *args):
self.warn_and_quit(EXIT_TIMEOUT, "timeout: server did not respond")
def do_command(self):
cr = self.server_capabilities.listget("command_response")
if cr is None:
self.warn_and_quit(EXIT_UNSUPPORTED, "server does not support control command")
return
code, text = cr
text = bytestostr(text)
if code!=0:
log.warn("server returned error code %s", code)
self.warn_and_quit(EXIT_REMOTE_ERROR, " %s" % text)
return
self.warn_and_quit(EXIT_OK, text)
def make_hello(self):
capabilities = GObjectXpraClient.make_hello(self)
log("make_hello() adding command request '%s' to %s", self.command, capabilities)
capabilities["command_request"] = self.command
return capabilities
class PrintClient(SendCommandConnectClient):
""" Allows us to send a file to the server for printing.
"""
def set_command_args(self, command):
log("set_command_args(%s)", command)
self.filename = command[0]
#print command arguments:
#filename, file_data, mimetype, source_uuid, title, printer, no_copies, print_options_str = packet[1:9]
self.command = command[1:]
#FIXME: load as needed...
from xpra.os_util import load_binary_file
if self.filename=="-":
#replace with filename proposed
self.filename = command[2]
#read file from stdin
self.file_data = sys.stdin.read()
log("read %i bytes from stdin", len(self.file_data))
else:
self.file_data = load_binary_file(self.filename)
log("read %i bytes from %s", len(self.file_data), self.filename)
if len(self.file_data)>=self.file_size_limit*1024*1024:
self.warn_and_quit(EXIT_FILE_TOO_BIG, "the file is too large: %iMB (the file size limit is %iMB)" % (len(self.file_data)//1024//1024, self.file_size_limit))
return
assert self.file_data, "no data found for '%s'" % self.filename
def client_type(self):
return "Python/GObject/Print"
def timeout(self, *args):
self.warn_and_quit(EXIT_TIMEOUT, "timeout: server did not respond")
def do_command(self):
printing = self.server_capabilities.boolget("printing")
if not printing:
self.warn_and_quit(EXIT_UNSUPPORTED, "server does not support printing")
return
#TODO: compress file data? (this should run locally most of the time anyway)
from xpra.net.compression import Compressed
blob = Compressed("print", self.file_data)
self.send("print", self.filename, blob, *self.command)
log("print: sending %s as %s for printing", self.filename, blob)
self.idle_add(self.send, "disconnect", DONE, "detaching")
def make_hello(self):
capabilities = SendCommandConnectClient.make_hello(self)
capabilities["wants_features"] = True #so we know if printing is supported or not
capabilities["print_request"] = True #marker to skip full setup
return capabilities
class ExitXpraClient(SendCommandConnectClient):
""" This client does one thing only:
it asks the server to terminate (like stop),
but without killing the Xvfb or clients.
"""
def timeout(self, *args):
self.warn_and_quit(EXIT_TIMEOUT, "timeout: server did not disconnect us")
def make_hello(self):
capabilities = SendCommandConnectClient.make_hello(self)
capabilities["exit_request"] = True
return capabilities
def do_command(self):
self.idle_add(self.send, "exit-server")
class StopXpraClient(SendCommandConnectClient):
""" stop a server """
def make_hello(self):
#used for telling the proxy server we want "stop"
#(as waiting for the hello back would be too late)
capabilities = SendCommandConnectClient.make_hello(self)
capabilities["stop_request"] = True
return capabilities
def timeout(self, *args):
self.warn_and_quit(EXIT_TIMEOUT, "timeout: server did not disconnect us")
def do_command(self):
self.idle_add(self.send, "shutdown-server")
#not exiting the client here,
#the server should send us the shutdown disconnection message anyway
#and if not, we will then hit the timeout to tell us something went wrong
class DetachXpraClient(SendCommandConnectClient):
""" run the detach subcommand """
def make_hello(self):
#used for telling the proxy server we want "detach"
#(older versions ignore this flag and detach because this is a new valid connection
# but this breaks if sharing is enabled!)
capabilities = SendCommandConnectClient.make_hello(self)
capabilities["detach_request"] = True
return capabilities
def timeout(self, *args):
self.warn_and_quit(EXIT_TIMEOUT, "timeout: server did not disconnect us")
def do_command(self):
self.idle_add(self.send, "disconnect", DONE, "detaching")
#not exiting the client here,
#the server should disconnect us with the response
|