This file is indexed.

/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