def parse_client_caps(self, c: typedict): #general features: self.info_namespace = c.boolget("info-namespace") self.share = c.boolget("share") self.lock = c.boolget("lock") self.control_commands = c.strtupleget("control_commands") self.xdg_menu_update = c.boolget("xdg-menu-update") bandwidth_limit = c.intget("bandwidth-limit", 0) server_bandwidth_limit = self.server_bandwidth_limit if self.server_bandwidth_limit is None: server_bandwidth_limit = self.get_socket_bandwidth_limit( ) or bandwidth_limit self.bandwidth_limit = min(server_bandwidth_limit, bandwidth_limit) if self.bandwidth_detection: self.bandwidth_detection = c.boolget("bandwidth-detection", True) self.client_connection_data = c.dictget("connection-data", {}) ccd = typedict(self.client_connection_data) self.adapter_type = ccd.strget("adapter-type", "") self.jitter = ccd.intget("jitter", 0) bandwidthlog( "server bandwidth-limit=%s, client bandwidth-limit=%s, value=%s, detection=%s", server_bandwidth_limit, bandwidth_limit, self.bandwidth_limit, self.bandwidth_detection) if getattr(self, "mmap_size", 0) > 0: log("mmap enabled, ignoring bandwidth-limit") self.bandwidth_limit = 0
def parse_client_caps(self, c: typedict): self.uuid = c.strget("uuid") self.session_id = c.strget("session-id") self.machine_id = c.strget("machine_id") self.hostname = c.strget("hostname") self.username = c.strget("username") self.name = c.strget("name") self.argv = c.strtupleget("argv") self.sharing = c.boolget("share") self.client_type = c.strget("client_type", "PyGTK") self.client_platform = c.strget("platform") self.client_machine = c.strget("platform.machine") self.client_processor = c.strget("platform.processor") self.client_release = c.strget("platform.sysrelease") self.client_linux_distribution = c.strtupleget( "platform.linux_distribution") self.client_version = c.strget("version") self.client_revision = c.strget("build.revision") self.client_bits = c.intget("python.bits") self.client_proxy = c.boolget("proxy") self.client_wm_name = c.strget("wm_name") self.client_session_type = c.strget("session-type") self.client_session_type_full = c.strget("session-type.full", "") self.client_setting_change = c.boolget("setting-change") self.client_opengl = typedict(c.dictget("opengl") or {}) self.proxy_hostname = c.strget("proxy.hostname") self.proxy_platform = c.strget("proxy.platform") self.proxy_release = c.strget("proxy.platform.sysrelease") self.proxy_version = c.strget("proxy.version") self.proxy_version = c.strget("proxy.build.version", self.proxy_version) log("client uuid %s", self.uuid)
def parse_server_capabilities(self, c: typedict) -> bool: if self.remote_logging.lower( ) in ("send", "both", "yes", "true", "on") and ( #'remote-logging.receive' was only added in v4.1 so check both: c.boolget("remote-logging") or c.boolget("remote-logging.receive")): #check for debug: from xpra.log import is_debug_enabled conflict = tuple(v for v in ("network", "crypto", "udp", "websocket") if is_debug_enabled(v)) if conflict: log.warn("Warning: cannot enable remote logging") log.warn(" because debug logging is enabled for: %s", csv(conflict)) return True log.info("enabled remote logging") if not self.log_both: log.info(" see server log file for further output") self.local_logging = set_global_logging_handler( self.remote_logging_handler) elif self.remote_logging.lower() == "receive": self.request_server_log = c.boolget("remote-logging.send") if not self.request_server_log: log.warn("Warning: cannot receive log output from the server") log.warn( " the feature is not enabled or not supported by the server" ) else: self.after_handshake(self.start_receiving_logging) #pylint: disable=no-member return True
def process_ui_capabilities(self, c : typedict): self.server_is_desktop = c.boolget("shadow") or c.boolget("desktop") skip_vfb_size_check = False #if we decide not to use scaling, skip warnings if not fequ(self.xscale, 1.0) or not fequ(self.yscale, 1.0): #scaling is used, make sure that we need it and that the server can support it #(without rounding support, size-hints can cause resize loops) if self.server_is_desktop and not self.desktop_fullscreen: #don't honour auto mode in this case if self.desktop_scaling=="auto": log.info(" not scaling a %s server", c.strget("type", "shadow")) skip_vfb_size_check = self.xscale>1 or self.yscale>1 self.scale_change_embargo = 0 self.scalingoff() if self.can_scale: self.may_adjust_scaling() if not self.server_is_desktop and not skip_vfb_size_check and self.server_max_desktop_size: avail_w, avail_h = self.server_max_desktop_size root_w, root_h = self.get_root_size() log("validating server_max_desktop_size=%s vs root size=%s", self.server_max_desktop_size, (root_w, root_h)) if self.cx(root_w)!=root_w or self.cy(root_h)!=root_h: log(" root size scaled to %s", (self.cx(root_w), self.cy(root_h))) if self.cx(root_w)>(avail_w+1) or self.cy(root_h)>(avail_h+1): log.warn("Server's virtual screen is too small") log.warn(" server: %sx%s vs client: %sx%s", avail_w, avail_h, self.cx(root_w), self.cy(root_h)) log.warn(" you may see strange behavior,") log.warn(" please see https://github.com/Xpra-org/xpra/blob/master/docs/Usage/Xdummy.md") #now that we have the server's screen info, allow scale changes: self.scale_change_embargo = 0 self.set_max_packet_size()
def parse_server_capabilities(self, c: typedict) -> bool: #make sure the server doesn't provide a start time in the future: import time self.server_start_time = min(time.time(), c.intget("start_time", -1)) self.server_bandwidth_limit_change = c.boolget( "network.bandwidth-limit-change") self.server_bandwidth_limit = c.intget("network.bandwidth-limit") bandwidthlog( "server_bandwidth_limit_change=%s, server_bandwidth_limit=%s", self.server_bandwidth_limit_change, self.server_bandwidth_limit) self.server_packet_encoders = tuple(x for x in ALL_ENCODERS if c.boolget(x, False)) return True
def parse_server_capabilities(self, c: typedict) -> bool: try: from xpra import clipboard assert clipboard except ImportError: log.warn("Warning: clipboard module is missing") self.clipboard_enabled = False return True self.server_clipboard = c.boolget("clipboard") self.server_clipboard_loop_uuids = c.dictget("clipboard.loop-uuids", {}) self.server_clipboard_direction = c.strget("clipboard-direction", "both") if self.server_clipboard_direction != self.client_clipboard_direction and self.server_clipboard_direction != "both": if self.client_clipboard_direction == "disabled": pass elif self.server_clipboard_direction == "disabled": log.warn( "Warning: server clipboard synchronization is currently disabled" ) self.client_clipboard_direction = "disabled" elif self.client_clipboard_direction == "both": log.warn( "Warning: server only supports '%s' clipboard transfers", self.server_clipboard_direction) self.client_clipboard_direction = self.server_clipboard_direction else: log.warn("Warning: incompatible clipboard direction settings") log.warn(" server setting: %s, client setting: %s", self.server_clipboard_direction, self.client_clipboard_direction) try: from xpra.clipboard.clipboard_core import ALL_CLIPBOARDS except ImportError: ALL_CLIPBOARDS = [] self.server_clipboards = c.strtupleget("clipboards", ALL_CLIPBOARDS) log("server clipboard: supported=%s, direction=%s", self.server_clipboard, self.server_clipboard_direction) log("client clipboard: supported=%s, direction=%s", self.client_supports_clipboard, self.client_clipboard_direction) self.clipboard_enabled = self.client_supports_clipboard and self.server_clipboard log("parse_clipboard_caps() clipboard enabled=%s", self.clipboard_enabled) self.server_clipboard_contents_slice_fix = c.boolget( "clipboard.contents-slice-fix") self.server_clipboard_preferred_targets = c.strtupleget( "clipboard.preferred-targets", ()) if not self.server_clipboard_contents_slice_fix: log.info("server clipboard does not include contents slice fix") return True
def parse_client_caps(self, c: typedict): self.clipboard_enabled = c.boolget("clipboard", False) self.clipboard_notifications = c.boolget("clipboard.notifications") log("client clipboard: enabled=%s, notifications=%s", self.clipboard_enabled, self.clipboard_notifications) self.clipboard_greedy = c.boolget("clipboard.greedy") self.clipboard_want_targets = c.boolget("clipboard.want_targets") self.clipboard_selections = c.strtupleget("clipboard.selections", CLIPBOARDS) self.clipboard_preferred_targets = c.strtupleget( "clipboard.preferred-targets", ()) log("client clipboard: greedy=%s, want_targets=%s, selections=%s", self.clipboard_greedy, self.clipboard_want_targets, self.clipboard_selections)
def parse_client_caps(self, c : typedict): self.clipboard_enabled = c.boolget("clipboard", False) self.clipboard_notifications = c.boolget("clipboard.notifications") log("client clipboard: enabled=%s, notifications=%s", self.clipboard_enabled, self.clipboard_notifications) self.clipboard_greedy = c.boolget("clipboard.greedy") self.clipboard_want_targets = c.boolget("clipboard.want_targets") self.clipboard_client_selections = c.strtupleget("clipboard.selections", CLIPBOARDS) self.clipboard_contents_slice_fix = c.boolget("clipboard.contents-slice-fix") self.clipboard_preferred_targets = c.strtupleget("clipboard.preferred-targets", ()) log("client clipboard: greedy=%s, want_targets=%s, client_selections=%s, contents_slice_fix=%s", self.clipboard_greedy, self.clipboard_want_targets, self.clipboard_client_selections, self.clipboard_contents_slice_fix) if self.clipboard_enabled and not self.clipboard_contents_slice_fix: log.info("client clipboard does not include contents slice fix")
def parse_server_capabilities(self, c: typedict) -> bool: self.mmap_enabled = self.supports_mmap and self.mmap_enabled and c.boolget( "mmap_enabled") log("parse_server_capabilities(..) mmap_enabled=%s", self.mmap_enabled) if self.mmap_enabled: from xpra.net.mmap_pipe import read_mmap_token, DEFAULT_TOKEN_INDEX, DEFAULT_TOKEN_BYTES def iget(attrname, default_value=0): return c.intget("mmap_%s" % attrname) or c.intget( "mmap.%s" % attrname) or default_value mmap_token = iget("token") mmap_token_index = iget("token_index", DEFAULT_TOKEN_INDEX) mmap_token_bytes = iget("token_bytes", DEFAULT_TOKEN_BYTES) token = read_mmap_token(self.mmap, mmap_token_index, mmap_token_bytes) if token != mmap_token: log.error("Error: mmap token verification failed!") log.error(" expected '%#x'", token) log.error(" found '%#x'", mmap_token) self.mmap_enabled = False self.quit(EXIT_MMAP_TOKEN_FAILURE) return log.info( "enabled fast mmap transfers using %sB shared memory area", std_unit(self.mmap_size, unit=1024)) #the server will have a handle on the mmap file by now, safe to delete: if not KEEP_MMAP_FILE: self.clean_mmap() return True
def parse_server_capabilities(self, caps: typedict) -> bool: for c in XpraClientBase.__bases__: if not c.parse_server_capabilities(self, caps): return False self.server_client_shutdown = caps.boolget("client-shutdown", True) self.server_compressors = caps.strtupleget("compressors", ("zlib", )) return True
def parse_server_capabilities(self, c : typedict) -> bool: for bc in XpraClientBase.__bases__: if not bc.parse_server_capabilities(self, c): log.info("server capabilities rejected by %s", bc) return False self.server_client_shutdown = c.boolget("client-shutdown", True) self.server_compressors = c.strtupleget("compressors", ("zlib",)) return True
def parse_hello(self, c: typedict): self.ui_client = c.boolget("ui_client", True) self.wants_encodings = c.boolget("wants_encodings", self.ui_client) self.wants_display = c.boolget("wants_display", self.ui_client) self.wants_events = c.boolget("wants_events", False) self.wants_aliases = c.boolget("wants_aliases", True) self.wants_versions = c.boolget("wants_versions", True) self.wants_features = c.boolget("wants_features", True) self.wants_default_cursor = c.boolget("wants_default_cursor", False) for bc in CC_BASES: log("%s.parse_client_caps(..)", bc) bc.parse_client_caps(self, c) #log client info: cinfo = self.get_connect_info() for i, ci in enumerate(cinfo): log.info("%s%s", ["", " "][int(i > 0)], ci) if self.client_proxy: from xpra.version_util import version_compat_check msg = version_compat_check(self.proxy_version) if msg: proxylog = Logger("proxy") proxylog.warn( "Warning: proxy version may not be compatible: %s", msg)
def parse_server_capabilities(self, c: typedict) -> bool: self.server_dbus_proxy = c.boolget("dbus_proxy") #default for pre-0.16 servers: if self.server_dbus_proxy: default_rpc_types = ["dbus"] else: default_rpc_types = [] self.server_rpc_types = c.strtupleget("rpc-types", default_rpc_types) return True
def parse_client_caps(self, c: typedict): av_sync = c.boolget("av-sync") self.av_sync_enabled = self.av_sync and av_sync self.set_av_sync_delay( int(self.av_sync_enabled) * c.intget("av-sync.delay.default", DEFAULT_AV_SYNC_DELAY)) log("av-sync: server=%s, client=%s, enabled=%s, total=%s", self.av_sync, av_sync, self.av_sync_enabled, self.av_sync_delay_total)
def parse_client_caps(self, c: typedict): self.randr_notify = c.boolget("randr_notify") self.desktop_size = c.intpair("desktop_size") if self.desktop_size is not None: w, h = self.desktop_size if w <= 0 or h <= 0 or w >= 32768 or h >= 32768: log.warn("ignoring invalid desktop dimensions: %sx%s", w, h) self.desktop_size = None self.desktop_mode_size = c.intpair("desktop_mode_size") self.desktop_size_unscaled = c.intpair("desktop_size.unscaled") self.screen_resize_bigger = c.boolget("screen-resize-bigger", True) self.set_screen_sizes(c.tupleget("screen_sizes")) self.set_desktops(c.intget("desktops", 1), c.strtupleget("desktop.names")) self.show_desktop_allowed = c.boolget("show-desktop") self.icc = c.dictget("icc", {}) self.display_icc = c.dictget("display-icc", {}) self.opengl_props = c.dictget("opengl", {})
def parse_printing_capabilities(self, caps : typedict): printlog("parse_printing_capabilities() client printing support=%s", self.printing) if self.printing: server_printing = caps.boolget("printing") printlog("parse_printing_capabilities() server printing support=%s", server_printing) if server_printing: self.printer_attributes = caps.strtupleget("printer.attributes", ("printer-info", "device-uri")) self.timeout_add(1000, self.init_printing)
def parse_server_capabilities(self, c : typedict) -> bool: self.server_webcam = c.boolget("webcam") self.server_webcam_encodings = c.strtupleget("webcam.encodings", ("png", "jpeg")) self.server_virtual_video_devices = c.intget("virtual-video-devices") log("webcam server support: %s (%i devices, encodings: %s)", self.server_webcam, self.server_virtual_video_devices, csv(self.server_webcam_encodings)) if self.webcam_forwarding and self.server_webcam and self.server_virtual_video_devices>0: if self.webcam_option=="on" or self.webcam_option.find("/dev/video")>=0: self.start_sending_webcam() return True
def parse_server_capabilities(self, c : typedict) -> bool: try: from xpra import clipboard assert clipboard except ImportError: log.warn("Warning: clipboard module is missing") self.clipboard_enabled = False return True self.server_clipboard = c.boolget("clipboard") self.server_clipboard_direction = c.strget("clipboard-direction", "both") if self.server_clipboard_direction!=self.client_clipboard_direction and self.server_clipboard_direction!="both": if self.client_clipboard_direction=="disabled": pass elif self.server_clipboard_direction=="disabled": log.warn("Warning: server clipboard synchronization is currently disabled") self.client_clipboard_direction = "disabled" elif self.client_clipboard_direction=="both": log.warn("Warning: server only supports '%s' clipboard transfers", self.server_clipboard_direction) self.client_clipboard_direction = self.server_clipboard_direction else: log.warn("Warning: incompatible clipboard direction settings") log.warn(" server setting: %s, client setting: %s", self.server_clipboard_direction, self.client_clipboard_direction) try: from xpra.clipboard.clipboard_core import ALL_CLIPBOARDS except ImportError: ALL_CLIPBOARDS = [] self.server_clipboards = c.strtupleget("clipboards", ALL_CLIPBOARDS) log("server clipboard: supported=%s, direction=%s", self.server_clipboard, self.server_clipboard_direction) log("client clipboard: supported=%s, direction=%s", self.client_supports_clipboard, self.client_clipboard_direction) self.clipboard_enabled = self.client_supports_clipboard and self.server_clipboard self.server_clipboard_greedy = c.boolget("clipboard.greedy") self.server_clipboard_want_targets = c.boolget("clipboard.want_targets") self.server_clipboard_selections = c.strtupleget("clipboard.selections", CLIPBOARDS) self.server_clipboard_preferred_targets = c.strtupleget("clipboard.preferred-targets", ()) log("server clipboard: greedy=%s, want_targets=%s, selections=%s", self.server_clipboard_greedy, self.server_clipboard_want_targets, self.server_clipboard_selections) log("parse_clipboard_caps() clipboard enabled=%s", self.clipboard_enabled) self.server_clipboard_preferred_targets = c.strtupleget("clipboard.preferred-targets", ()) return True
def is_needed(cls, caps: typedict) -> bool: #the 'webcam' capability was only added in v4, #so we have to enable the mixin by default: if not caps.boolget("webcam", True): return False try: from xpra.codecs.pillow.decoder import HEADERS assert HEADERS except ImportError: return False return True
def do_command(self, caps : typedict): printing = caps.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 parse_server_capabilities(self, c : typedict) -> bool: self.server_display = c.strget("display") self.server_desktop_size = c.intpair("desktop_size") log("server desktop size=%s", self.server_desktop_size) self.server_max_desktop_size = c.intpair("max_desktop_size", (2**15, 2**15)) self.server_actual_desktop_size = c.intpair("actual_desktop_size") log("server actual desktop size=%s", self.server_actual_desktop_size) self.server_randr = c.boolget("resize_screen") log("server has randr: %s", self.server_randr) self.server_opengl = c.dictget("opengl") return True
def parse_server_capabilities(self, c: typedict) -> bool: self.server_av_sync = c.boolget("av-sync.enabled") avsynclog("av-sync: server=%s, client=%s", self.server_av_sync, self.av_sync) self.server_pulseaudio_id = c.strget("sound.pulseaudio.id") self.server_pulseaudio_server = c.strget("sound.pulseaudio.server") self.server_sound_decoders = c.strtupleget("sound.decoders") self.server_sound_encoders = c.strtupleget("sound.encoders") self.server_sound_receive = c.boolget("sound.receive") self.server_sound_send = c.boolget("sound.send") self.server_sound_bundle_metadata = c.boolget("sound.bundle-metadata") log( "pulseaudio id=%s, server=%s, sound decoders=%s, sound encoders=%s, receive=%s, send=%s", self.server_pulseaudio_id, self.server_pulseaudio_server, csv(self.server_sound_decoders), csv(self.server_sound_encoders), self.server_sound_receive, self.server_sound_send) if self.server_sound_send and self.speaker_enabled: self.start_receiving_sound() if self.server_sound_receive and self.microphone_enabled: self.start_sending_sound() return True
def parse_server_capabilities(self, c: typedict) -> bool: self.server_av_sync = c.boolget("av-sync.enabled") avsynclog("av-sync: server=%s, client=%s", self.server_av_sync, self.av_sync) self.server_pulseaudio_id = c.strget("sound.pulseaudio.id") self.server_pulseaudio_server = c.strget("sound.pulseaudio.server") self.server_sound_decoders = c.strtupleget("sound.decoders") self.server_sound_encoders = c.strtupleget("sound.encoders") self.server_sound_receive = c.boolget("sound.receive") self.server_sound_send = c.boolget("sound.send") log( "pulseaudio id=%s, server=%s, sound decoders=%s, sound encoders=%s, receive=%s, send=%s", self.server_pulseaudio_id, self.server_pulseaudio_server, csv(self.server_sound_decoders), csv(self.server_sound_encoders), self.server_sound_receive, self.server_sound_send) if self.server_sound_send and self.speaker_enabled: self.show_progress(90, "starting speaker forwarding") self.start_receiving_sound() if self.server_sound_receive and self.microphone_enabled: #call via idle_add because we may query X11 properties #to find the pulseaudio server: GLib.idle_add(self.start_sending_sound) return True
def do_command(self, caps : typedict): if not caps.boolget("shell"): msg = "this server does not support the 'shell' subcommand" log.error(msg) self.disconnect_and_quit(EXIT_UNSUPPORTED, msg) return #start reading from stdin: self.install_signal_handlers() stdin = sys.stdin fileno = stdin.fileno() import fcntl fl = fcntl.fcntl(fileno, fcntl.F_GETFL) fcntl.fcntl(fileno, fcntl.F_SETFL, fl | os.O_NONBLOCK) self.stdin_io_watch = GLib.io_add_watch(sys.stdin, GLib.PRIORITY_DEFAULT, GLib.IO_IN, self.stdin_ready) self.print_prompt()
def parse_server_capabilities(self, c: typedict) -> bool: if self.client_supports_remote_logging and c.boolget("remote-logging"): #check for debug: from xpra.log import is_debug_enabled conflict = tuple(v for v in ("network", "crypto", "udp", "websocket") if is_debug_enabled(v)) if conflict: log.warn("Warning: cannot enable remote logging") log.warn(" because debug logging is enabled for: %s", csv(conflict)) return True log.info("enabled remote logging") if not self.log_both: log.info(" see server log file for further output") self.local_logging = set_global_logging_handler( self.remote_logging_handler) return True
def parse_client_caps(self, c: typedict): #general features: self.info_namespace = c.boolget("info-namespace") self.send_notifications = c.boolget("notifications") self.send_notifications_actions = c.boolget("notifications.actions") log("notifications=%s, actions=%s", self.send_notifications, self.send_notifications_actions) self.share = c.boolget("share") self.lock = c.boolget("lock") self.control_commands = c.strtupleget("control_commands") self.xdg_menu_update = c.boolget("xdg-menu-update") bandwidth_limit = c.intget("bandwidth-limit", 0) server_bandwidth_limit = self.server_bandwidth_limit if self.server_bandwidth_limit is None: server_bandwidth_limit = self.get_socket_bandwidth_limit( ) or bandwidth_limit self.bandwidth_limit = min(server_bandwidth_limit, bandwidth_limit) if self.bandwidth_detection: self.bandwidth_detection = c.boolget("bandwidth-detection", True) self.client_connection_data = c.dictget("connection-data", {}) self.jitter = typedict(self.client_connection_data).intget("jitter", 0) bandwidthlog( "server bandwidth-limit=%s, client bandwidth-limit=%s, value=%s, detection=%s", server_bandwidth_limit, bandwidth_limit, self.bandwidth_limit, self.bandwidth_detection) if getattr(self, "mmap_size", 0) > 0: log("mmap enabled, ignoring bandwidth-limit") self.bandwidth_limit = 0 #adjust max packet size if file transfers are enabled: #TODO: belongs in mixin: file_transfer = getattr(self, "file_transfer", None) if file_transfer: self.protocol.max_packet_size = max( self.protocol.max_packet_size, self.file_size_limit * 1024 * 1024)
def is_needed(cls, caps: typedict) -> bool: #the 'keyboard' and 'mouse' capability were only added in v4, #so we have to enable the mixin by default: return caps.boolget("keyboard", True) or caps.boolget( "mouse", True) or caps.boolget("windows", False)
def is_needed(cls, caps: typedict) -> bool: return caps.boolget("windows")
def parse_client_caps(self, c : typedict): self.pointer_relative = c.boolget("pointer.relative") self.double_click_time = c.intget("double_click.time") self.double_click_distance = c.intpair("double_click.distance") self.mouse_show = c.boolget("mouse.show") self.mouse_last_position = c.intpair("mouse.initial-position")
def is_needed(cls, caps: typedict) -> bool: return caps.boolget("sound.send") or caps.boolget("sound.receive")