Package x2go :: Module session
[frames] | no frames]

Source Code for Module x2go.session

   1  # -*- coding: utf-8 -*- 
   2   
   3  # Copyright (C) 2010-2012 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> 
   4  # 
   5  # Python X2Go is free software; you can redistribute it and/or modify 
   6  # it under the terms of the GNU Affero General Public License as published by 
   7  # the Free Software Foundation; either version 3 of the License, or 
   8  # (at your option) any later version. 
   9  # 
  10  # Python X2Go is distributed in the hope that it will be useful, 
  11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  13  # GNU Affero General Public License for more details. 
  14  # 
  15  # You should have received a copy of the GNU Affero General Public License 
  16  # along with this program; if not, write to the 
  17  # Free Software Foundation, Inc., 
  18  # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 
  19   
  20  """\ 
  21  X2goSession class - a public API of Python X2Go, handling standalone X2Go  
  22  sessions. 
  23   
  24  This class is normally embedded into the context of an L{X2goClient} 
  25  instance, but it is also possible to address L{X2goSession}s directly via this 
  26  class. 
  27   
  28  To launch a session manually from the Python interactive shell, perform these 
  29  simple steps:: 
  30   
  31    $ python 
  32    Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)  
  33    [GCC 4.4.5] on linux2 
  34    Type "help", "copyright", "credits" or "license" for more information. 
  35    >>> import x2go 
  36    >>> import gevent 
  37    Xlib.protocol.request.QueryExtension 
  38    >>> s = x2go.session.X2goSession() 
  39    >>> s.set_server('<my.x2go.server>') 
  40    >>> s.set_port(<ssh-port>) 
  41    >>> s.connect('<my-login>', '<my-password>') 
  42    [<pidno>] (x2gocontrolsession-pylib) NOTICE: connecting to [<my.x2go.server>]:<ssh-port> 
  43    [<pidno>] (x2gosession-pylib) NOTICE: SSH host key verification for host [<my.x2go.server>]:<ssh-port> with SSH-RSA fingerprint ,,<ssh-fingerprint>'' initiated. We are seeing this X2Go server for the first time. 
  44    [<pidno>] (x2gosession-pylib) WARN: HOOK_check_host_dialog: host check requested for [<my.x2go.server>]:<ssh-port> with SSH-RSA fingerprint: ,,<ssh-fingerprint>''. Automatically adding host as known host. 
  45    True 
  46    >>> s.start(cmd="LXDE") 
  47    True 
  48    >>> while True: gevent.sleep(1) 
  49   
  50  """ 
  51   
  52  __NAME__ = 'x2gosession-pylib' 
  53   
  54  import os 
  55  import copy 
  56  import types 
  57  import uuid 
  58  import time 
  59  import gevent 
  60  import re 
  61  import threading 
  62   
  63  # FIXME: we need the list of keys from a potentially used SSH agent. This part of code has to be moved into the control session code 
  64  import paramiko 
  65   
  66  # Python X2Go modules 
  67  import defaults 
  68  import log 
  69  import utils 
  70  import session 
  71  import x2go_exceptions 
  72   
  73  from x2go.backends.control import X2goControlSession as _X2goControlSession 
  74  from x2go.backends.terminal import X2goTerminalSession as _X2goTerminalSession 
  75  from x2go.backends.info import X2goServerSessionInfo as _X2goServerSessionInfo 
  76  from x2go.backends.info import X2goServerSessionList as _X2goServerSessionList 
  77  from x2go.backends.proxy import X2goProxy as _X2goProxy 
  78  from x2go.backends.settings import X2goClientSettings as _X2goClientSettings 
  79  from x2go.backends.printing import X2goClientPrinting as _X2goClientPrinting 
  80   
  81  from defaults import X2GOCLIENT_OS as _X2GOCLIENT_OS 
  82  from defaults import LOCAL_HOME as _LOCAL_HOME 
  83  from defaults import X2GO_CLIENT_ROOTDIR as _X2GO_CLIENT_ROOTDIR 
  84  from defaults import X2GO_SESSIONS_ROOTDIR as _X2GO_SESSIONS_ROOTDIR 
  85  from defaults import X2GO_SSH_ROOTDIR as _X2GO_SSH_ROOTDIR 
  86   
  87  from defaults import SUPPORTED_SOUND, SUPPORTED_PRINTING, SUPPORTED_FOLDERSHARING, SUPPORTED_MIMEBOX 
  88   
  89  _X2GO_SESSION_PARAMS = ('use_sshproxy', 'sshproxy_reuse_authinfo', 
  90                          'profile_id', 'session_name', 
  91                          'auto_start_or_resume', 'auto_connect', 
  92                          'printing', 'allow_mimebox', 
  93                          'mimebox_extensions', 'mimebox_action', 
  94                          'allow_share_local_folders', 'share_local_folders', 'restore_shared_local_folders', 
  95                          'control_backend', 'terminal_backend', 'info_backend', 'list_backend', 'proxy_backend', 'settings_backend', 'printing_backend', 
  96                          'client_rootdir', 'sessions_rootdir', 'ssh_rootdir', 
  97                          'keep_controlsession_alive', 'add_to_known_hosts', 'known_hosts', 'forward_sshagent', 
  98                          'connected', 'virgin', 'running', 'suspended', 'terminated', 'faulty' 
  99                          'client_instance', 
 100                         ) 
 101  """A list of allowed X2Go pure session parameters (i.e. parameters that are passed on neither to an X2goControlSession, X2goSSHProxy nor an X2goControlSession object.""" 
 102  # options of the paramiko.SSHClient().connect() method, any option that is allowed for a terminal session instance 
 103  _X2GO_TERMINAL_PARAMS = ('geometry', 'depth', 'link', 'pack', 'dpi', 
 104                           'cache_type', 'kbtype', 'kblayout', 'kbvariant', 
 105                           'session_type', 'snd_system', 'snd_port', 
 106                           'cmd', 'set_session_title', 'session_title', 
 107                           'rdp_server', 'rdp_options', 'applications', 
 108                           'xdmcp_server', 
 109                           'rootdir', 'loglevel', 'profile_name', 'profile_id', 
 110                           'print_action', 'print_action_args', 
 111                           'convert_encoding', 'client_encoding', 'server_encoding', 
 112                           'proxy_options', 'published_applications', 'published_applications_no_submenus', 
 113                           'logger', 
 114                           'control_backend', 'terminal_backend', 'proxy_backend', 
 115                           'profiles_backend', 'settings_backend', 'printing_backend', 
 116                          ) 
 117  """A list of allowed X2Go terminal session parameters.""" 
 118  _X2GO_SSHPROXY_PARAMS = ('sshproxy_host', 'sshproxy_port', 'sshproxy_user', 'sshproxy_password', 
 119                           'sshproxy_key_filename', 'sshproxy_pkey', 
 120                           'sshproxy_look_for_keys', 'sshproxy_allow_agent', 
 121                           'sshproxy_tunnel', 
 122                          ) 
 123  """A list of allowed X2Go SSH proxy parameters.""" 
 124   
 125   
126 -class X2goSession(object):
127 """\ 128 Public API class for launching X2Go sessions. Recommended is to manage X2Go sessions from 129 within an L{X2goClient} instance. However, Python X2Go is designed in a way that it also 130 allows the management of singel L{X2goSession} instance. 131 132 Thus, you can use the L{X2goSession} class to manually set up X2Go sessions without 133 L{X2goClient} context (session registry, session list cache, auto-registration of new 134 sessions etc.). 135 136 """
137 - def __init__(self, server=None, port=22, control_session=None, 138 use_sshproxy=False, 139 sshproxy_reuse_authinfo=False, 140 profile_id=None, profile_name='UNKNOWN', 141 session_name=None, 142 auto_start_or_resume=False, 143 auto_connect=False, 144 printing=False, 145 allow_mimebox=False, 146 mimebox_extensions=[], 147 mimebox_action='OPEN', 148 allow_share_local_folders=False, 149 share_local_folders=[], 150 restore_shared_local_folders=False, 151 control_backend=_X2goControlSession, 152 terminal_backend=_X2goTerminalSession, 153 info_backend=_X2goServerSessionInfo, 154 list_backend=_X2goServerSessionList, 155 proxy_backend=_X2goProxy, 156 settings_backend=_X2goClientSettings, 157 printing_backend=_X2goClientPrinting, 158 client_rootdir=os.path.join(_LOCAL_HOME, _X2GO_CLIENT_ROOTDIR), 159 sessions_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SESSIONS_ROOTDIR), 160 ssh_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SSH_ROOTDIR), 161 keep_controlsession_alive=False, 162 add_to_known_hosts=False, 163 known_hosts=None, 164 forward_sshagent=False, 165 logger=None, loglevel=log.loglevel_DEFAULT, 166 connected=False, activated=False, virgin=True, running=None, suspended=None, terminated=None, faulty=None, 167 client_instance=None, 168 **params):
169 """\ 170 @param server: hostname of X2Go server 171 @type server: C{str} 172 @param control_session: an already initialized C{X2goControlSession*} instance 173 @type control_session: C{X2goControlSession*} instance 174 @param use_sshproxy: for communication with X2Go server use an SSH proxy host 175 @type use_sshproxy: C{bool} 176 @param sshproxy_reuse_authinfo: for proxy authentication re-use the X2Go session's password / key file 177 @type sshproxy_reuse_authinfo: C{bool} 178 @param profile_id: profile ID 179 @type profile_id: C{str} 180 @param profile_name: profile name 181 @type profile_name: C{str} 182 @param session_name: session name (if available) 183 @type session_name: C{str} 184 @param auto_start_or_resume: automatically start a new or resume latest session after connect 185 @type auto_start_or_resume: C{bool} 186 @param auto_connect: call a hook method that handles connecting the session profile automatically after a session for this profile has been registered 187 @type auto_connect: C{bool} 188 @param printing: enable X2Go printing 189 @type printing: C{bool} 190 @param allow_mimebox: enable X2Go MIME box support 191 @type allow_mimebox: C{bool} 192 @param mimebox_extensions: whitelist of allowed X2Go MIME box extensions 193 @type mimebox_extensions: C{list} 194 @param mimebox_action: action for incoming X2Go MIME box files 195 @type mimebox_action: C{X2goMimeBoxAction*} or C{str} 196 @param allow_share_local_folders: enable local folder sharing support 197 @type allow_share_local_folders: C{bool} 198 @param share_local_folders: list of local folders to share with the remote X2Go session 199 @type share_local_folders: C{list} 200 @param restore_shared_local_folders: store actual list of shared local folders after session has been suspended or terminated 201 @type restore_shared_local_folders: C{bool} 202 @param control_backend: X2Go control session backend to use 203 @type control_backend: C{class} 204 @param terminal_backend: X2Go terminal session backend to use 205 @type terminal_backend: C{class} 206 @param info_backend: X2Go session info backend to use 207 @type info_backend: C{class} 208 @param list_backend: X2Go session list backend to use 209 @type list_backend: C{class} 210 @param proxy_backend: X2Go proxy backend to use 211 @type proxy_backend: C{class} 212 @param settings_backend: X2Go client settings backend to use 213 @type settings_backend: C{class} 214 @param printing_backend: X2Go client printing backend to use 215 @type printing_backend: C{class} 216 @param client_rootdir: client base dir (default: ~/.x2goclient) 217 @type client_rootdir: C{str} 218 @param sessions_rootdir: sessions base dir (default: ~/.x2go) 219 @type sessions_rootdir: C{str} 220 @param ssh_rootdir: ssh base dir (default: ~/.ssh) 221 @type ssh_rootdir: C{str} 222 @param keep_controlsession_alive: On last L{X2goSession.disconnect()} keep the associated C{X2goControlSession*} instance alive? 223 @ŧype keep_controlsession_alive: C{bool} 224 @param add_to_known_hosts: Auto-accept server host validity? 225 @type add_to_known_hosts: C{bool} 226 @param known_hosts: the underlying Paramiko/SSH systems C{known_hosts} file 227 @type known_hosts: C{str} 228 @param forward_sshagent: forward SSH agent authentication requests to the SSH agent on the X2Go client-side 229 @type forward_sshagent: C{bool} 230 @param connected: manipulate session state »connected« by giving a pre-set value 231 @type connected: C{bool} 232 @param activated: normal leave this untouched, an activated session is a session that is about to be used 233 @type activated: C{bool} 234 @param virgin: manipulate session state »virgin« by giving a pre-set value 235 @type virgin: C{bool} 236 @param running: manipulate session state »running« by giving a pre-set value 237 @type running: C{bool} 238 @param suspended: manipulate session state »suspended« by giving a pre-set value 239 @type suspended: C{bool} 240 @param terminated: manipulate session state »terminated« by giving a pre-set value 241 @type terminated: C{bool} 242 @param faulty: manipulate session state »faulty« by giving a pre-set value 243 @type faulty: C{bool} 244 @param client_instance: if available, the underlying L{X2goClient} instance 245 @type client_instance: C{X2goClient} instance 246 @param params: further control session, terminal session and SSH proxy class options 247 @type params: C{dict} 248 249 """ 250 if logger is None: 251 self.logger = log.X2goLogger(loglevel=loglevel) 252 else: 253 self.logger = copy.deepcopy(logger) 254 self.logger.tag = __NAME__ 255 256 self._keep = None 257 258 self.uuid = uuid.uuid1() 259 self.connected = connected 260 261 self.activated = activated 262 self.virgin = virgin 263 self.running = running 264 self.suspended = suspended 265 self.terminated = terminated 266 self.faulty = faulty 267 self.keep_controlsession_alive = keep_controlsession_alive 268 269 self.profile_id = profile_id 270 self.profile_name = profile_name 271 self.session_name = session_name 272 self.server = server 273 self.port = port 274 275 self._last_status = None 276 277 self.locked = False 278 279 self.auto_start_or_resume = auto_start_or_resume 280 self.auto_connect = auto_connect 281 self.printing = printing 282 self.allow_share_local_folders = allow_share_local_folders 283 self.share_local_folders = share_local_folders 284 self.restore_shared_local_folders = restore_shared_local_folders 285 self.allow_mimebox = allow_mimebox 286 self.mimebox_extensions = mimebox_extensions 287 self.mimebox_action = mimebox_action 288 self.control_backend = control_backend 289 self.terminal_backend = terminal_backend 290 self.info_backend = info_backend 291 self.list_backend = list_backend 292 self.proxy_backend = proxy_backend 293 self.settings_backend = settings_backend 294 self.printing_backend = printing_backend 295 self.client_rootdir = client_rootdir 296 self.sessions_rootdir = sessions_rootdir 297 self.ssh_rootdir = ssh_rootdir 298 self.control_session = control_session 299 300 if params.has_key('published_applications'): 301 self.published_applications = params['published_applications'] 302 if self.published_applications: 303 params['cmd'] = 'PUBLISHED' 304 else: 305 self.published_applications = params['published_applications'] = False 306 307 if params.has_key('cmd') and params['cmd'] != 'PUBLISHED': 308 self.published_applications = params['published_applications'] = False 309 self.published_applications_menu = None 310 311 if self.session_name: 312 if not re.match('.*_stRPUBLISHED_.*',self.session_name): 313 self.published_applications = params['published_applications'] = False 314 315 self.use_sshproxy = use_sshproxy 316 self.sshproxy_reuse_authinfo = sshproxy_reuse_authinfo 317 318 self.control_params = {} 319 self.terminal_params = {} 320 self.sshproxy_params = {} 321 self.update_params(params) 322 self.shared_folders = {} 323 324 self.session_environment = {} 325 self.server_features = [] 326 327 try: del self.control_params['server'] 328 except: pass 329 330 self.client_instance = client_instance 331 332 if self.logger.get_loglevel() & log.loglevel_DEBUG: 333 self.logger('X2Go control session parameters for profile %s:' % profile_name, loglevel=log.loglevel_DEBUG) 334 for p in self.control_params: 335 self.logger(' %s: %s' % (p, self.control_params[p]), log.loglevel_DEBUG) 336 self.logger('X2Go terminal session parameters for profile %s:' % profile_name, loglevel=log.loglevel_DEBUG) 337 for p in self.terminal_params: 338 self.logger(' %s: %s' % (p,self.terminal_params[p]), log.loglevel_DEBUG) 339 self.logger('X2Go sshproxy parameters for profile %s:' % profile_name, loglevel=log.loglevel_DEBUG) 340 for p in self.sshproxy_params: 341 self.logger(' %s: %s' % (p,self.sshproxy_params[p]), loglevel=log.loglevel_DEBUG) 342 343 self.add_to_known_hosts = add_to_known_hosts 344 self.known_hosts = known_hosts 345 self.forward_sshagent = forward_sshagent 346 347 self._current_status = { 348 'timestamp': time.time(), 349 'server': self.server, 350 'virgin': self.virgin, 351 'connected': self.connected, 352 'running': self.running, 353 'suspended': self.suspended, 354 'terminated': self.terminated, 355 'faulty': self.faulty, 356 } 357 358 self._SUPPORTED_SOUND = SUPPORTED_SOUND 359 self._SUPPORTED_PRINTING = SUPPORTED_PRINTING 360 self._SUPPORTED_MIMEBOX = SUPPORTED_MIMEBOX 361 self._SUPPORTED_FOLDERSHARING = SUPPORTED_FOLDERSHARING 362 363 self.master_session = None 364 self.init_control_session() 365 self.terminal_session = None 366 367 if self.is_connected(): 368 self.retrieve_server_features() 369 370 self._progress_status = 0 371 self._lock = threading.Lock() 372 373 if self.client_instance and self.restore_shared_local_folders: 374 self._restore_exported_folders = self.client_instance.get_profile_config(self.profile_name, 'export')
375
376 - def __str__(self):
377 return self.__get_uuid()
378
379 - def __repr__(self):
380 result = 'X2goSession(' 381 for p in dir(self): 382 if '__' in p or not p in self.__dict__ or type(p) is types.InstanceType: continue 383 result += p + '=' + str(self.__dict__[p]) + ',' 384 result = result.strip(',') 385 return result + ')'
386
387 - def __call__(self):
388 return self.__get_uuid()
389
390 - def __del__(self):
391 """\ 392 Class destructor. 393 394 """ 395 if self.has_control_session() and self.has_terminal_session(): 396 self.get_control_session().dissociate(self.get_terminal_session()) 397 398 if self.has_control_session(): 399 if self.keep_controlsession_alive: 400 # regenerate this session instance for re-usage if this is the last session for a certain session profile 401 # and keep_controlsession_alive is set to True... 402 self.virgin = True 403 self.activated = False 404 self.connected = self.is_connected() 405 self.running = None 406 self.suspended = None 407 self.terminated = None 408 self._current_status = { 409 'timestamp': time.time(), 410 'server': self.server, 411 'virgin': self.virgin, 412 'connected': self.connected, 413 'running': self.running, 414 'suspended': self.suspended, 415 'terminated': self.terminated, 416 'faulty': self.faulty, 417 } 418 self._last_status = None 419 self.session_name = None 420 421 else: 422 self.get_control_session().__del__() 423 self.control_session = None 424 425 if self.has_terminal_session(): 426 self.get_terminal_session().__del__() 427 self.terminal_session = None
428
429 - def get_client_instance(self):
430 """\ 431 Return parent L{X2goClient} instance if avaiable. 432 433 return: L{X2goClient} instance this session is associated with 434 rtype: C{obj} 435 436 """ 437 return self.client_instance
438 __get_client_instance = get_client_instance 439
441 """\ 442 HOOK method: called if a control session (server connection) has unexpectedly encountered a failure. 443 444 """ 445 if self.client_instance: 446 self.client_instance.HOOK_on_control_session_death(profile_name=self.profile_name) 447 else: 448 self.logger('HOOK_on_control_session_death: the control session of profile %s has died unexpectedly' % self.profile_name, loglevel=log.loglevel_WARN)
449
450 - def HOOK_auto_connect(self):
451 """\ 452 HOOK method: called if the session demands to auto connect. 453 454 """ 455 if self.client_instance: 456 self.client_instance.HOOK_profile_auto_connect(profile_name=self.profile_name) 457 else: 458 self.logger('HOOK_auto_connect: profile ,,%s\'\' wants to auto-connect to the X2Go server.' % self.profile_name, loglevel=log.loglevel_WARN)
459
461 """\ 462 HOOK method: called if the startup of a session failed. 463 464 """ 465 if self.client_instance: 466 self.client_instance.HOOK_session_startup_failed(profile_name=self.profile_name) 467 else: 468 self.logger('HOOK_session_startup_failed: session startup for session profile ,,%s\'\' failed.' % self.profile_name, loglevel=log.loglevel_WARN)
469
470 - def HOOK_rforward_request_denied(self, server_port=0):
471 """\ 472 HOOK method: called if a reverse port forwarding request has been denied. 473 474 @param server_port: remote server port (starting point of reverse forwarding tunnel) 475 @type server_port: C{str} 476 477 """ 478 if self.client_instance: 479 self.client_instance.HOOK_rforward_request_denied(profile_name=self.profile_name, session_name=self.session_name, server_port=server_port) 480 else: 481 self.logger('HOOK_rforward_request_denied: TCP port (reverse) forwarding request for session %s to server port %s has been denied by server %s. This is a common issue with SSH, it might help to restart the server\'s SSH daemon.' % (self.session_name, server_port, self.profile_name), loglevel=log.loglevel_WARN)
482
483 - def HOOK_forwarding_tunnel_setup_failed(self, chain_host='UNKNOWN', chain_port=0):
484 """\ 485 HOOK method: called if a port forwarding tunnel setup failed. 486 487 @param chain_host: hostname of chain host (forwarding tunnel end point) 488 @type chain_host: C{str} 489 @param chain_port: port of chain host (forwarding tunnel end point) 490 @type chain_port: C{str} 491 492 """ 493 # mark session as faulty 494 self.faulty = True 495 496 if self.client_instance: 497 self.client_instance.HOOK_forwarding_tunnel_setup_failed(profile_name=self.profile_name, session_name=self.session_name, chain_host=chain_host, chain_port=chain_port) 498 else: 499 self.logger('HOOK_forwarding_tunnel_setup_failed: Forwarding tunnel request to [%s]:%s for session %s (%s) was denied by remote X2go/SSH server. Session startup failed.' % (chain_host, chain_port, self.session_name, self.profile_name), loglevel=log.loglevel_WARN) 500 501 # get rid of the faulty session... 502 try: 503 self._terminate() 504 except x2go_exceptions.X2goSessionException: 505 pass
506
508 """\ 509 HOOK method: called if X2Go client-side printing is not available. 510 511 """ 512 if self.client_instance: 513 self.client_instance.HOOK_printing_not_available(profile_name=self.profile_name, session_name=self.session_name) 514 else: 515 self.logger('HOOK_printing_not_available: X2Go\'s client-side printing feature is not available with this session (%s) of profile %s.' % (self.session_name, self.profile_name), loglevel=log.loglevel_WARN)
516
517 - def HOOK_mimebox_not_available(self):
518 """\ 519 HOOK method: called if the X2Go MIME box is not available. 520 521 """ 522 if self.client_instance: 523 self.client_instance.HOOK_mimebox_not_available(profile_name=self.profile_name, session_name=self.session_name) 524 else: 525 self.logger('HOOK_mimebox_not_available: X2Go\'s MIME box feature is not available with this session (%s) of profile %s.' % (self.session_name, self.profile_name), loglevel=log.loglevel_WARN)
526
528 """\ 529 HOOK method: called if X2Go client-side folder-sharing is not available. 530 531 """ 532 if self.client_instance: 533 self.client_instance.HOOK_foldersharing_not_available(profile_name=self.profile_name, session_name=self.session_name) 534 else: 535 self.logger('HOOK_foldersharing_not_available: X2Go\'s client-side folder sharing feature is not available with this session (%s) of profile %s.' % (self.session_name, self.profile_name), loglevel=log.loglevel_WARN)
536
537 - def HOOK_sshfs_not_available(self):
538 """\ 539 HOOK method: called if the X2Go server denies SSHFS access. 540 541 """ 542 if self.client_instance: 543 self.client_instance.HOOK_sshfs_not_available(profile_name=self.profile_name, session_name=self.session_name) 544 else: 545 self.logger('HOOK_sshfs_not_available: the remote X2Go server (%s) denies SSHFS access for session %s. This will result in client-side folder sharing, printing and the MIME box feature being unavailable' % (self.profile_name, self.session_name), loglevel=log.loglevel_WARN)
546
547 - def HOOK_check_host_dialog(self, host, port, fingerprint='no fingerprint', fingerprint_type='RSA'):
548 """\ 549 HOOK method: called if a host check is requested. This hook has to either return C{True} (default) or C{False}. 550 551 @param host: SSH server name to validate 552 @type host: C{str} 553 @param port: SSH server port to validate 554 @type port: C{int} 555 @param fingerprint: the server's fingerprint 556 @type fingerprint: C{str} 557 @param fingerprint_type: finger print type (like RSA, DSA, ...) 558 @type fingerprint_type: C{str} 559 @return: if host validity is verified, this hook method should return C{True} 560 @rtype: C{bool} 561 562 """ 563 if self.client_instance: 564 return self.client_instance.HOOK_check_host_dialog(profile_name=self.profile_name, host=host, port=port, fingerprint=fingerprint, fingerprint_type=fingerprint_type) 565 else: 566 self.logger('HOOK_check_host_dialog: host check requested for [%s]:%s with %s fingerprint: ,,%s\'\'. Automatically adding host as known host.' % (host, port, fingerprint_type, fingerprint), loglevel=log.loglevel_WARN) 567 return True
568
569 - def init_control_session(self):
570 """\ 571 Initialize a new control session (C{X2goControlSession*}). 572 573 """ 574 if self.control_session is None: 575 self.logger('initializing X2goControlSession', loglevel=log.loglevel_DEBUG) 576 self.control_session = self.control_backend(profile_name=self.profile_name, 577 add_to_known_hosts=self.add_to_known_hosts, 578 known_hosts=self.known_hosts, 579 forward_sshagent=self.forward_sshagent, 580 terminal_backend=self.terminal_backend, 581 info_backend=self.info_backend, 582 list_backend=self.list_backend, 583 proxy_backend=self.proxy_backend, 584 client_rootdir=self.client_rootdir, 585 sessions_rootdir=self.sessions_rootdir, 586 ssh_rootdir=self.ssh_rootdir, 587 logger=self.logger)
588 __init_control_session = init_control_session 589
590 - def is_master_session(self):
591 """\ 592 Is this session a/the master session of sessions. 593 594 The master session is the session has been launched first for a specific connection, 595 it also is _the_ session that controls the client-side shared folders. 596 597 If this L{X2goSession} instance is a standalone instance (without parent L{X2goClient}) 598 this method will always return C{True}. 599 600 @return: returns C{True} if this session is a master session 601 @rtype: C{bool} 602 603 """ 604 if self.master_session is None and self.client_instance is None: 605 return True 606 return bool(self.master_session)
607 __is_master_session = is_master_session 608
609 - def set_master_session(self, wait=0, max_wait=20):
610 """\ 611 Declare this as a master session of a connection channel. 612 613 This method gets called by the L{X2goSessionRegistry} while sessions are starting or resuming and it relies on 614 an already set-up terminal session. 615 616 @param wait: wait for <wait> seconds before sharing local folders via the new master session 617 of the corresponding session profile. 618 @type wait: C{int} 619 @param max_wait: wait for <max_wait> seconds for the terminal session to appear 620 @type max_wait: C{int} 621 622 """ 623 self.logger('Using session %s as master session for profile %s.' % (self.get_session_name(), self.get_profile_name()), loglevel=log.loglevel_NOTICE) 624 self.master_session = True 625 626 # retrieve an up-to-date list of sharable local folders from the client instance 627 if self.client_instance: 628 _exports = self.client_instance.get_profile_config(self.profile_name, 'export') 629 self.share_local_folders = [ sf for sf in _exports.keys() if _exports[sf] ] 630 631 i = 0 632 while i < max_wait: 633 i += 1 634 if self.has_terminal_session(): 635 break 636 gevent.sleep(1) 637 638 if wait: 639 gevent.spawn_later(wait, self.share_all_local_folders, update_exported_folders=False) 640 else: 641 gevent.spawn(self.share_all_local_folders, update_exported_folders=False)
642 __set_master_session = set_master_session 643
644 - def unset_master_session(self):
645 """\ 646 Declare this as a non-master session of a connection channel. 647 648 """ 649 # unmount shared folders 650 if self.has_terminal_session(): 651 self.unshare_all_local_folders(update_exported_folders=False) 652 self.master_session = False
653 __unset_master_session = unset_master_session 654
655 - def set_server(self, server):
656 """\ 657 Modify server name after L{X2goSession} has already been initialized. 658 659 @param server: new server name 660 @type server: C{str} 661 662 """ 663 self.server = server
664 __set_server = set_server 665
666 - def set_port(self, port):
667 """\ 668 Modify server port after L{X2goSession} has already been initialized. 669 670 @param port: socket port of server to connect to 671 @type port: C{int} 672 673 """ 674 self.port = port
675 __set_port = set_port 676
677 - def set_profile_name(self, profile_name):
678 """\ 679 Modify session profile name after L{X2goSession} has already been initialized. 680 681 @param profile_name: new session profile name 682 @type profile_name: C{str} 683 684 """ 685 self.profile_name = profile_name 686 self.control_session.set_profile_name(profile_name)
687 __set_profile_name = set_profile_name 688
689 - def get_session_profile_option(self, option):
690 """\ 691 Retrieve a specific profile parameter for this session. 692 693 @param option: name of a specific profile option to be queried. 694 @type option: C{str} 695 696 @return: value for profile option C{<option>} 697 @rtype: C{bool,str,int} 698 699 @raise X2goProfileException: if the session profile option is unknown 700 701 """ 702 if option in _X2GO_SESSION_PARAMS + _X2GO_TERMINAL_PARAMS + _X2GO_SSHPROXY_PARAMS and hasattr(self, option): 703 return eval("self.%s" % option) 704 else: 705 raise x2go_exceptions.X2goProfileException('Unknown session profile option: %s.' % option)
706 __get_session_profile_option = get_session_profile_option 707
708 - def update_params(self, params):
709 """\ 710 This method can be used to modify L{X2goSession} parameters after the 711 L{X2goSession} instance has already been initialized. 712 713 @param params: a Python dictionary with L{X2goSession} parameters 714 @type params: C{dict} 715 716 """ 717 try: del params['server'] 718 except KeyError: pass 719 try: del params['profile_name'] 720 except KeyError: pass 721 try: del params['profile_id'] 722 except KeyError: pass 723 try: 724 self.printing = params['printing'] 725 del params['printing'] 726 except KeyError: pass 727 try: 728 self.allow_share_local_folders = params['allow_share_local_folders'] 729 del params['allow_share_local_folders'] 730 except KeyError: pass 731 try: 732 self.share_local_folders = params['share_local_folders'] 733 del params['share_local_folders'] 734 except KeyError: pass 735 try: 736 self.restore_shared_local_folders = params['restore_shared_local_folders'] 737 del params['restore_shared_local_folders'] 738 except KeyError: pass 739 try: 740 self.allow_mimebox = params['allow_mimebox'] 741 del params['allow_mimebox'] 742 except KeyError: pass 743 try: 744 self.mimebox_extensions = params['mimebox_extensions'] 745 del params['mimebox_extensions'] 746 except KeyError: pass 747 try: 748 self.mimebox_action = params['mimebox_action'] 749 del params['mimebox_action'] 750 except KeyError: pass 751 try: 752 self.use_sshproxy = params['use_sshproxy'] 753 del params['use_sshproxy'] 754 except KeyError: pass 755 try: 756 self.sshproxy_reuse_authinfo = params['sshproxy_reuse_authinfo'] 757 del params['sshproxy_reuse_authinfo'] 758 except KeyError: pass 759 try: 760 self.auto_connect = params['auto_connect'] 761 del params['auto_connect'] 762 except KeyError: pass 763 try: 764 self.forward_sshagent = params['forward_sshagent'] 765 del params['forward_sshagent'] 766 except KeyError: pass 767 try: 768 self.auto_start_or_resume = params['auto_start_or_resume'] 769 del params['auto_start_or_resume'] 770 except KeyError: pass 771 772 if self.sshproxy_reuse_authinfo: 773 if params.has_key('key_filename'): 774 params['sshproxy_key_filename'] = params['key_filename'] 775 if params.has_key('pkey'): 776 params['sshproxy_pkey'] = params['pkey'] 777 if params.has_key('password'): 778 params['sshproxy_password'] = params['password'] 779 780 _terminal_params = copy.deepcopy(params) 781 _control_params = copy.deepcopy(params) 782 _sshproxy_params = copy.deepcopy(params) 783 for p in params.keys(): 784 if p in session._X2GO_TERMINAL_PARAMS: 785 del _control_params[p] 786 del _sshproxy_params[p] 787 elif p in session._X2GO_SSHPROXY_PARAMS: 788 del _control_params[p] 789 del _terminal_params[p] 790 else: 791 del _sshproxy_params[p] 792 del _terminal_params[p] 793 794 self.control_params.update(_control_params) 795 self.terminal_params.update(_terminal_params) 796 self.sshproxy_params.update(_sshproxy_params)
797
798 - def get_uuid(self):
799 """\ 800 Retrieve session UUID hash for this L{X2goSession}. 801 802 @return: the session's UUID hash 803 @rtype: C{str} 804 805 """ 806 return str(self.uuid)
807 __get_uuid = get_uuid 808
809 - def get_username(self):
810 """\ 811 After a session has been set up you can query the 812 username the session runs as. 813 814 @return: the remote username the X2Go session runs as 815 @rtype: C{str} 816 817 """ 818 # try to retrieve the username from the control session, if already connected 819 try: 820 return self.control_session.get_transport().get_username() 821 except AttributeError: 822 return self.control_params['username']
823 __get_username = get_username 824
825 - def user_is_x2gouser(self, username=None):
826 """\ 827 Check if a given user is valid server-side X2Go user. 828 829 @param username: username to check validity for 830 @type username: C{str} 831 832 @return: C{True} if the username is allowed to launch X2Go sessions 833 @rtype: C{bool} 834 835 """ 836 if username is None: 837 username = self.__get_username() 838 return self.control_session.is_x2gouser(username)
839 __user_is_x2gouser = user_is_x2gouser 840
841 - def get_password(self):
842 """\ 843 After a session has been setup up you can query the 844 username's password from the session. 845 846 @return: the username's password 847 @rtype: C{str} 848 849 """ 850 return self.control_session._session_password
851 __get_password = get_password 852
853 - def get_server_peername(self):
854 """\ 855 After a session has been setup up you can query the 856 peername of the host this session is connected to (or 857 about to connect to). 858 859 @return: the address of the server the X2Go session is 860 connected to (as an C{(addr,port)} tuple) 861 @rtype: C{tuple} 862 863 """ 864 return self.control_session.remote_peername()
865 __get_server_peername = get_server_peername 866 remote_peername = get_server_peername 867 __remote_peername = get_server_peername 868
869 - def get_server_hostname(self):
870 """\ 871 After a session has been setup up you can query the 872 hostname of the host this session is connected to (or 873 about to connect to). 874 875 @return: the hostname of the server the X2Go session is 876 connected to / about to connect to 877 @rtype: C{str} 878 879 """ 880 self.server = self.control_session.get_hostname() 881 return self.server
882 __get_server_hostname = get_server_hostname 883
884 - def get_server_port(self):
885 """\ 886 After a session has been setup up you can query the 887 IP socket port used for connecting the remote X2Go server. 888 889 @return: the server-side IP socket port that is used by the X2Go session to 890 connect to the server 891 @rtype: C{str} 892 893 """ 894 return self.control_session.get_port()
895 __get_server_port = get_server_port 896
897 - def get_session_name(self):
898 """\ 899 Retrieve the server-side X2Go session name for this session. 900 901 @return: X2Go session name 902 @rtype: C{str} 903 904 """ 905 return self.session_name
906 __get_session_name = get_session_name 907
908 - def set_session_name(self, session_name):
909 """\ 910 Manipulate the L{X2GoSession}'s session name. 911 912 @param session_name: the new session name to be set 913 @type session_name: C{str} 914 915 """ 916 self.session_name = session_name
917 __set_session_name = set_session_name 918
919 - def get_session_info(self):
920 """\ 921 Retrieve the server-side X2Go session info object for this session. 922 923 @return: X2Go session info 924 @rtype: C{obj} 925 926 """ 927 if self.has_terminal_session(): 928 self.terminal_session.get_session_info()
929 __get_session_info = get_session_info 930
931 - def get_session_cmd(self):
932 """\ 933 Retrieve the server-side command that is used to start a session 934 on the remote X2Go server. 935 936 @return: server-side session command 937 @rtype: C{str} 938 939 """ 940 if self.has_terminal_session(): 941 return self.terminal_session.get_session_cmd() 942 if self.terminal_params.has_key('cmd'): 943 return self.terminal_params['cmd'] 944 return None
945 __get_session_cmd = get_session_cmd 946
947 - def get_session_type(self):
948 """\ 949 Retrieve the session type of a session (R, D, S or P). 950 951 - R: rootless session 952 - D: desktop session 953 - S: shadow session 954 - P: session in published applications mode 955 956 @return: session type 957 @rtype: C{str} 958 959 """ 960 if self.has_terminal_session(): 961 return self.terminal_session.get_session_type() 962 else: 963 return None
964 __get_session_type = get_session_type 965
966 - def get_session_title(self):
967 """\ 968 Retrieve the session window title of this 969 session. 970 971 @return: session window title 972 @rtype: C{str} 973 974 """ 975 if self.has_terminal_session(): 976 return self.terminal_session.session_title 977 else: 978 return 'X2GO-%s' % self.get_session_name()
979 __get_session_title = get_session_title 980
981 - def get_control_session(self):
982 """\ 983 Retrieve the control session (C{X2goControlSession*} backend) of this L{X2goSession}. 984 985 @return: the L{X2goSession}'s control session 986 @rtype: C{X2goControlSession*} instance 987 988 """ 989 return self.control_session
990 __get_control_session = get_control_session 991
992 - def has_control_session(self):
993 """\ 994 Check if this L{X2goSession} instance has an associated control session. 995 996 @return: returns C{True} if this L{X2goSession} has a control session associated to itself 997 @rtype: C{bool} 998 999 """ 1000 return self.control_session is not None
1001 __has_control_session = has_control_session 1002
1003 - def get_terminal_session(self):
1004 """\ 1005 Retrieve the terminal session (C{X2goTerminalSession*} backend) of this L{X2goSession}. 1006 1007 @return: the L{X2goSession}'s terminal session 1008 @rtype: C{X2goControlTerminal*} instance 1009 1010 """ 1011 if self.terminal_session == 'PENDING': 1012 return None 1013 return self.terminal_session
1014 __get_terminal_session = get_terminal_session 1015
1016 - def has_terminal_session(self):
1017 """\ 1018 Check if this L{X2goSession} instance has an associated terminal session. 1019 1020 @return: returns C{True} if this L{X2goSession} has a terminal session associated to itself 1021 @rtype: C{bool} 1022 1023 """ 1024 return self.terminal_session not in (None, 'PENDING')
1025 __has_terminal_session = has_terminal_session 1026 is_associated = has_terminal_session 1027 __is_associated = has_terminal_session 1028
1029 - def check_host(self):
1030 """\ 1031 Provide a host check mechanism. This method basically calls the L{HOOK_check_host_dialog()} method 1032 which by itself calls the L{X2goClient.HOOK_check_host_dialog()} method. Make sure you 1033 override any of these to enable user interaction on X2Go server validity checks. 1034 1035 @return: returns C{True} if an X2Go server host is valid for authentication 1036 @rtype: C{bool} 1037 1038 """ 1039 if self.connected: 1040 return True 1041 1042 _port = self.control_params['port'] 1043 (_valid, _host, _port, _fingerprint, _fingerprint_type) = self.control_session.check_host(self.server, port=_port) 1044 return _valid or self.HOOK_check_host_dialog(host=_host, port=_port, fingerprint=_fingerprint, fingerprint_type=_fingerprint_type)
1045 __check_host = check_host 1046
1047 - def uses_sshproxy(self):
1048 """\ 1049 Check if a session is configured to use an intermediate SSH proxy server. 1050 1051 @return: returns C{True} if the session is configured to use an SSH proxy, C{False} otherwise. 1052 @rtype: C{bool} 1053 1054 """ 1055 return self.use_sshproxy
1056 __uses_sshproxy = uses_sshproxy 1057
1058 - def reuses_sshproxy_authinfo(self):
1059 """\ 1060 Check if a session is configured to re-use the X2Go session's password / key for 1061 proxy authentication, as well. 1062 1063 @return: returns C{True} if the session is configured to re-use session password / key for proxy authentication 1064 @rtype: C{bool} 1065 1066 """ 1067 return self.sshproxy_reuse_authinfo
1068 __reuses_sshproxy_authinfo = reuses_sshproxy_authinfo 1069
1070 - def can_sshproxy_auto_connect(self):
1071 """\ 1072 Check if a session's SSH proxy (if used) is configured adequately to be able to auto-connect 1073 to the SSH proxy server (e.g. by public key authentication). 1074 1075 @return: returns C{True} if the session's SSH proxy can auto-connect, C{False} otherwise, C{None} 1076 if no SSH proxy is used for this session, C{None} is returned. 1077 @rtype: C{bool} 1078 1079 """ 1080 if self.use_sshproxy: 1081 if self.sshproxy_params.has_key('sshproxy_key_filename') and self.sshproxy_params['sshproxy_key_filename'] and os.path.exists(os.path.normpath(self.sshproxy_params['sshproxy_key_filename'])): 1082 return True 1083 elif self.sshproxy_reuse_authinfo and self.control_params.has_key('key_filename') and self.control_params['key_filename'] and os.path.exists(os.path.normpath(self.control_params['key_filename'])): 1084 return True 1085 elif self.sshproxy_params.has_key('sshproxy_pkey') and self.sshproxy_params['sshproxy_pkey']: 1086 return True 1087 elif self.sshproxy_reuse_authinfo and self.control_params.has_key('pkey') and self.control_params['pkey']: 1088 return True 1089 elif self.sshproxy_params.has_key('sshproxy_look_for_keys') and self.sshproxy_params['sshproxy_look_for_keys'] and (os.path.exists(os.path.expanduser('~/.ssh/id_rsa')) or os.path.exists(os.path.expanduser('~/.ssh/id_dsa'))): 1090 return True 1091 elif self.sshproxy_params.has_key('sshproxy_allow_agent') and self.sshproxy_params['sshproxy_allow_agent'] and paramiko.Agent().get_keys(): 1092 return True 1093 else: 1094 return False 1095 else: 1096 return None
1097 __can_sshproxy_auto_connect = can_sshproxy_auto_connect 1098
1099 - def can_auto_connect(self):
1100 """\ 1101 Check if a session is configured adequately to be able to auto-connect to the X2go 1102 server (e.g. public key authentication). 1103 1104 @return: returns C{True} if the session can auto-connect, C{False} otherwise, C{None} 1105 if no control session has been set up yet. 1106 @rtype: C{bool} 1107 1108 """ 1109 if self.control_session is None: 1110 return None 1111 1112 _can_sshproxy_auto_connect = self.can_sshproxy_auto_connect() 1113 1114 # do we have a key file passed as control parameter? 1115 if self.control_params.has_key('key_filename') and self.control_params['key_filename'] and os.path.exists(os.path.normpath(self.control_params['key_filename'])): 1116 return (_can_sshproxy_auto_connect is None) or _can_sshproxy_auto_connect 1117 1118 # or a private key? 1119 elif self.control_params.has_key('pkey') and self.control_params['pkey']: 1120 return (_can_sshproxy_auto_connect is None) or _can_sshproxy_auto_connect 1121 1122 # or a key auto discovery? 1123 elif self.control_params.has_key('look_for_keys') and self.control_params['look_for_keys'] and (os.path.exists(os.path.expanduser('~/.ssh/id_rsa')) or os.path.exists(os.path.expanduser('~/.ssh/id_dsa'))): 1124 return (_can_sshproxy_auto_connect is None) or _can_sshproxy_auto_connect 1125 1126 # or an SSH agent usage? 1127 elif self.control_params.has_key('allow_agent') and self.control_params['allow_agent'] and paramiko.Agent().get_keys(): 1128 return (_can_sshproxy_auto_connect is None) or _can_sshproxy_auto_connect 1129 1130 else: 1131 return False
1132 __can_auto_connect = can_auto_connect 1133
1134 - def do_auto_connect(self, redirect_to_client=True):
1135 """\ 1136 Automatically connect this session. 1137 1138 @return: Return success (or failure) of connecting this sessions 1139 @rtype: C{bool} 1140 1141 """ 1142 if not self.is_connected(): 1143 if self.client_instance and redirect_to_client: 1144 return self.client_instance.session_auto_connect(self()) 1145 else: 1146 if self.can_auto_connect() and self.auto_connect: 1147 gevent.spawn(self.connect) 1148 elif self.auto_connect: 1149 gevent.spawn(self.HOOK_auto_connect)
1150 __do_auto_connect = do_auto_connect 1151
1152 - def connect(self, username='', password='', add_to_known_hosts=False, force_password_auth=False, 1153 look_for_keys=None, allow_agent=None, 1154 use_sshproxy=None, sshproxy_reuse_authinfo=False, sshproxy_user='', sshproxy_password='', sshproxy_force_password_auth=False):
1155 """\ 1156 Connects to the L{X2goSession}'s server host. This method basically wraps around 1157 the C{X2goControlSession*.connect()} method. 1158 1159 @param username: the username for the X2Go server that is going to be 1160 connected to (as a last minute way of changing the session username) 1161 @type username: C{str} 1162 @param password: the user's password for the X2Go server that is going to be 1163 connected to 1164 @type password: C{str} 1165 @param add_to_known_hosts: non-paramiko option, if C{True} paramiko.AutoAddPolicy() 1166 is used as missing-host-key-policy. If set to C{False} paramiko.RejectPolicy() 1167 is used 1168 @type add_to_known_hosts: C{bool} 1169 @param force_password_auth: disable SSH pub/priv key authentication mechanisms 1170 completely 1171 @type force_password_auth: C{bool} 1172 @param look_for_keys: set to C{True} to enable searching for discoverable 1173 private key files in C{~/.ssh/} 1174 @type look_for_keys: C{bool} 1175 @param allow_agent: set to C{True} to enable connecting to a local SSH agent 1176 for acquiring authentication information 1177 @type allow_agent: C{bool} 1178 @param use_sshproxy: use an SSH proxy host for connecting the target X2Go server 1179 @type use_sshproxy: C{bool} 1180 @param sshproxy_reuse_authinfo: for proxy authentication re-use the X2Go session's password / key file 1181 @type sshproxy_reuse_authinfo: C{bool} 1182 @param sshproxy_user: username for authentication against the SSH proxy host 1183 @type sshproxy_user: C{str} 1184 @param sshproxy_password: password for authentication against the SSH proxy host 1185 @type sshproxy_password: C{str} 1186 @param sshproxy_force_password_auth: enforce password authentication even is a key(file) is present 1187 @type sshproxy_force_password_auth: C{bool} 1188 1189 @return: returns C{True} is the connection to the X2Go server has been successful 1190 @rtype C{bool} 1191 1192 @raise X2goSessionException: on control session exceptions 1193 @raise X2goRemoteHomeException: if the remote home directory does not exist 1194 @raise Exception: any other exception during connecting is passed through 1195 1196 """ 1197 if self.control_session and self.control_session.is_connected(): 1198 self.logger('control session is already connected, skipping authentication', loglevel=log.loglevel_DEBUG) 1199 self.connected = True 1200 else: 1201 1202 if use_sshproxy is not None: 1203 self.use_sshproxy = use_sshproxy 1204 1205 if sshproxy_reuse_authinfo is not None: 1206 self.sshproxy_reuse_authinfo = sshproxy_reuse_authinfo 1207 1208 if username: 1209 self.control_params['username'] = username 1210 if add_to_known_hosts is not None: 1211 self.control_params['add_to_known_hosts'] = add_to_known_hosts 1212 if force_password_auth is not None: 1213 self.control_params['force_password_auth'] = force_password_auth 1214 if look_for_keys is not None: 1215 self.control_params['look_for_keys'] = look_for_keys 1216 if allow_agent is not None: 1217 self.control_params['allow_agent'] = allow_agent 1218 1219 if sshproxy_user: 1220 self.sshproxy_params['sshproxy_user'] = sshproxy_user 1221 if sshproxy_password: 1222 self.sshproxy_params['sshproxy_password'] = sshproxy_password 1223 if sshproxy_force_password_auth: 1224 self.sshproxy_params['sshproxy_force_password_auth'] = sshproxy_force_password_auth 1225 1226 self.control_params['password'] = password 1227 1228 if self.sshproxy_reuse_authinfo: 1229 if self.control_params.has_key('key_filename'): 1230 self.sshproxy_params['sshproxy_key_filename'] = self.control_params['key_filename'] 1231 if self.control_params.has_key('pkey'): 1232 self.sshproxy_params['sshproxy_pkey'] = self.control_params['pkey'] 1233 if self.control_params.has_key('password'): 1234 self.sshproxy_params['sshproxy_password'] = self.control_params['password'] 1235 1236 _params = {} 1237 _params.update(self.control_params) 1238 _params.update(self.sshproxy_params) 1239 1240 if 'port' not in _params: 1241 _params['port'] = self.port 1242 1243 try: 1244 self.connected = self.control_session.connect(self.server, 1245 use_sshproxy=self.use_sshproxy, 1246 session_instance=self, 1247 forward_sshagent=self.forward_sshagent, 1248 **_params) 1249 except x2go_exceptions.X2goControlSessionException, e: 1250 raise x2go_exceptions.X2goSessionException(str(e)) 1251 except x2go_exceptions.X2goRemoteHomeException, e: 1252 self.disconnect() 1253 raise e 1254 except: 1255 # remove credentials immediately 1256 self.control_params['password'] = '' 1257 if self.sshproxy_params and self.sshproxy_params.has_key('sshproxy_password'): 1258 del self.sshproxy_params['sshproxy_password'] 1259 raise 1260 finally: 1261 # remove credentials immediately 1262 self.control_params['password'] = '' 1263 if self.sshproxy_params and self.sshproxy_params.has_key('sshproxy_password'): 1264 del self.sshproxy_params['sshproxy_password'] 1265 1266 if not self.connected: 1267 # then tidy up... 1268 self.disconnect() 1269 1270 self.get_server_hostname() 1271 1272 if self.connected: 1273 self.update_status() 1274 self.retrieve_server_features() 1275 if self.auto_start_or_resume: 1276 gevent.spawn(self.do_auto_start_or_resume) 1277 1278 return self.connected
1279 __connect = connect 1280
1281 - def disconnect(self):
1282 """\ 1283 Disconnect this L{X2goSession} instance. 1284 1285 @return: returns C{True} if the disconnect operation has been successful 1286 @rtype: C{bool} 1287 1288 """ 1289 self.connected = False 1290 self.running = None 1291 self.suspended = None 1292 self.terminated = None 1293 self.faults = None 1294 self.active = False 1295 self._lock.release() 1296 self.unset_master_session() 1297 try: 1298 self.update_status(force_update=True) 1299 except x2go_exceptions.X2goControlSessionException: 1300 pass 1301 retval = self.control_session.disconnect() 1302 return retval
1303 __disconnect = disconnect 1304
1305 - def retrieve_server_features(self):
1306 """\ 1307 Query the X2Go server for a list of supported features. 1308 1309 """ 1310 self.server_features = self.control_session.query_server_features()
1311 __retrieve_server_features = retrieve_server_features 1312
1313 - def get_server_features(self):
1314 """\ 1315 Return a list of X2Go server-sides features (supported functionalities). 1316 1317 @return: a C{list} of X2Go feature names 1318 @rtype: C{list} 1319 1320 """ 1321 return self.server_features
1322 __get_server_features = get_server_features 1323
1324 - def has_server_feature(self, feature):
1325 """\ 1326 Check if C{feature} is a present feature of the connected X2Go server. 1327 1328 @param feature: an X2Go server feature as found in C{$SHAREDIR/x2go/feature.d/*} 1329 @type feature: C{str} 1330 1331 @return: returns C{True} if the feature is present 1332 @rtype: C{bool} 1333 1334 """ 1335 return feature in self.get_server_features()
1336 __has_server_feature = has_server_feature 1337
1338 - def set_session_window_title(self, title=''):
1339 """\ 1340 Modify session window title. If the session ID does not occur in the 1341 given title, it will be prepended, so that every X2Go session window 1342 always contains the X2Go session ID of that window. 1343 1344 @param title: new title for session window 1345 @type title: C{str} 1346 1347 """ 1348 if self.terminal_session is not None: 1349 self.terminal_session.set_session_window_title(title=title)
1350 __set_session_window_title = set_session_window_title 1351
1352 - def raise_session_window(self):
1353 """\ 1354 Try to lift the session window above all other windows and bring 1355 it to focus. 1356 1357 """ 1358 if self.terminal_session is not None: 1359 self.terminal_session.raise_session_window()
1360 __raise_session_window = raise_session_window 1361
1362 - def set_print_action(self, print_action, **kwargs):
1363 """\ 1364 If X2Go client-side printing is enable within this X2Go session you can use 1365 this method to alter the way how incoming print spool jobs are handled/processed. 1366 1367 For further information, please refer to the documentation of the L{X2goClient.set_session_print_action()} 1368 method. 1369 1370 @param print_action: one of the named above print actions, either as string or class instance 1371 @type print_action: C{str} or C{instance} 1372 @param kwargs: additional information for the given print action (print 1373 action arguments), for possible print action arguments and their values see each individual 1374 print action class 1375 @type kwargs: C{dict} 1376 1377 """ 1378 if type(print_action) is not types.StringType: 1379 return False 1380 self.terminal_session.set_print_action(print_action, **kwargs)
1381 __set_print_action = set_print_action 1382
1383 - def is_alive(self):
1384 """\ 1385 Find out if this X2Go session is still alive (that is: connected to the server). 1386 1387 @return: returns C{True} if the server connection is still alive 1388 @rtype: C{bool} 1389 1390 """ 1391 self.connected = self.control_session.is_alive() 1392 if self.control_session.has_session_died(): 1393 self.HOOK_on_control_session_death() 1394 if not self.connected: 1395 self._X2goSession__disconnect() 1396 return self.connected
1397 __is_alive = is_alive 1398
1399 - def clean_sessions(self, destroy_terminals=True, published_applications=False):
1400 """\ 1401 Clean all running sessions for the authenticated user on the remote X2Go server. 1402 1403 @param destroy_terminals: destroy associated terminal sessions 1404 @type destroy_terminals: C{bool} 1405 @param published_applications: clean sessions that are published applications providers, too 1406 @type published_applications: C{bool} 1407 1408 """ 1409 if self.is_alive(): 1410 1411 # unmount shared folders 1412 if self.has_terminal_session(): 1413 self.unshare_all_local_folders(force_all=True) 1414 1415 self.control_session.clean_sessions(destroy_terminals=destroy_terminals, published_applications=published_applications) 1416 else: 1417 self._X2goSession__disconnect()
1418 __clean_sessions = clean_sessions 1419
1420 - def list_sessions(self, raw=False):
1421 """\ 1422 List all sessions on the remote X2Go server that are owned by the authenticated user 1423 1424 @param raw: if C{True} the output of this method equals 1425 the output of the server-side C{x2golistsessions} command 1426 @type raw: C{bool} 1427 1428 @return: a session list (as data object or list of strings when called with C{raw=True} option) 1429 @rtype: C{X2goServerSessionList*} instance or C{list} 1430 1431 """ 1432 try: 1433 return self.control_session.list_sessions(raw=raw) 1434 except x2go_exceptions.X2goControlSessionException: 1435 self.HOOK_on_control_session_death() 1436 self._X2goSession__disconnect() 1437 return None
1438 __list_sessions = list_sessions 1439
1440 - def list_desktops(self, raw=False):
1441 """\ 1442 List X2Go desktops sessions available for desktop sharing on the remote X2Go server. 1443 1444 @param raw: if C{True} the output of this method equals 1445 the output of the server-side C{x2golistdesktops} command 1446 @type raw: C{bool} 1447 1448 @return: a list of strings representing available desktop sessions 1449 @rtype: C{list} 1450 1451 """ 1452 try: 1453 return self.control_session.list_desktops(raw=raw) 1454 except x2go_exceptions.X2goControlSessionException: 1455 self.HOOK_on_control_session_death() 1456 self._X2goSession__disconnect() 1457 return None
1458 __list_desktops = list_desktops 1459
1460 - def list_mounts(self, raw=False):
1461 """\ 1462 Use the X2Go session registered under C{session_uuid} to 1463 retrieve its list of mounted client shares for that session. 1464 1465 @param raw: output the list of mounted client shares in X2go's 1466 raw C{x2golistmounts} format 1467 @type raw: C{bool} 1468 1469 @return: a list of strings representing mounted client shares for this session 1470 @rtype: C{list} 1471 1472 """ 1473 try: 1474 return self.control_session.list_mounts(self.session_name, raw=raw) 1475 except x2go_exceptions.X2goControlSessionException: 1476 self.HOOK_on_control_session_death() 1477 self._X2goSession__disconnect() 1478 return None
1479 __list_mounts = list_mounts 1480
1481 - def update_status(self, session_list=None, force_update=False):
1482 """\ 1483 Update the current session status. The L{X2goSession} instance uses an internal 1484 session status cache that allows to query the session status without the need 1485 of retrieving data from the remote X2Go server for each query. 1486 1487 The session status (if initialized properly with the L{X2goClient} constructor gets 1488 updated in regularly intervals. 1489 1490 In case you use the L{X2goSession} class in standalone instances (that is: without 1491 being embedded into an L{X2goSession} context) then run this method in regular 1492 intervals to make sure the L{X2goSession}'s internal status cache information 1493 is always up-to-date. 1494 1495 @param session_list: provide an C{X2goServerSessionList*} that refers to X2Go sessions we want to update. 1496 This option is mainly for reducing server/client traffic. 1497 @type session_list: C{X2goServerSessionList*} instance 1498 @param force_update: force a session status update, if if the last update is less then 1 second ago 1499 @type force_update: C{bool} 1500 1501 @raise Exception: any exception is passed through in case the session disconnected surprisingly 1502 or has been marked as faulty 1503 1504 """ 1505 if not force_update and self._last_status is not None: 1506 _status_update_timedelta = time.time() - self._last_status['timestamp'] 1507 1508 # skip this session status update if not longer than a second ago... 1509 if _status_update_timedelta < 1: 1510 self.logger('status update interval too short (%s), skipping status update this time...' % _status_update_timedelta, loglevel=log.loglevel_DEBUG) 1511 return False 1512 1513 e = None 1514 self._last_status = copy.deepcopy(self._current_status) 1515 if session_list is None: 1516 try: 1517 session_list = self.control_session.list_sessions() 1518 self.connected = True 1519 except x2go_exceptions.X2goControlSessionException, e: 1520 self.connected = False 1521 self.running = None 1522 self.suspended = None 1523 self.terminated = None 1524 self.faulty = None 1525 1526 if self.connected: 1527 try: 1528 _session_name = self.get_session_name() 1529 _session_info = session_list[_session_name] 1530 self.running = _session_info.is_running() 1531 self.suspended = _session_info.is_suspended() 1532 if not self.virgin: 1533 self.terminated = not (self.running or self.suspended) 1534 else: 1535 self.terminated = None 1536 except KeyError, e: 1537 self.running = False 1538 self.suspended = False 1539 if not self.virgin: 1540 self.terminated = True 1541 self.faulty = not (self.running or self.suspended or self.terminated or self.virgin) 1542 1543 self._current_status = { 1544 'timestamp': time.time(), 1545 'server': self.server, 1546 'virgin': self.virgin, 1547 'connected': self.connected, 1548 'running': self.running, 1549 'suspended': self.suspended, 1550 'terminated': self.terminated, 1551 'faulty': self.faulty, 1552 } 1553 1554 if (not self.connected or self.faulty) and e: 1555 raise e 1556 1557 return True
1558 __update_status = update_status 1559
1561 """\ 1562 Returns true if this session runs in published applications mode. 1563 1564 @return: returns C{True} if this session is a provider session for published applications. 1565 @rtype: C{bool} 1566 1567 """ 1568 if self.has_terminal_session() and self.is_running() : 1569 return self.terminal_session.is_published_applications_provider() 1570 return False
1571 __is_published_applications_provider = is_published_applications_provider 1572
1573 - def is_desktop_session(self):
1574 """\ 1575 Returns true if this session is configured as desktop session. 1576 1577 @return: returns C{True} if this session is a desktop session. 1578 @rtype: C{bool} 1579 1580 """ 1581 if self.has_terminal_session(): 1582 return self.terminal_session.is_desktop_session() 1583 return False
1584 __is_desktop_session = is_desktop_session 1585
1586 - def get_published_applications(self, lang=None, refresh=False, raw=False, very_raw=False, max_no_submenus=defaults.PUBAPP_MAX_NO_SUBMENUS):
1587 """\ 1588 Return a list of published menu items from the X2Go server 1589 for session type published applications. 1590 1591 @param lang: locale/language identifier 1592 @type lang: C{str} 1593 @param refresh: force reload of the menu tree from X2Go server 1594 @type refresh: C{bool} 1595 @param raw: retrieve a raw output of the server list of published applications 1596 @type raw: C{bool} 1597 @param very_raw: retrieve a very raw output of the server list of published applications (as-is output of x2gogetapps script) 1598 @type very_raw: C{bool} 1599 1600 @return: A C{list} of C{dict} elements. Each C{dict} elements has a 1601 C{desktop} key containing the text output of a .desktop file and 1602 an C{icon} key which contains the desktop icon data base64 encoded 1603 @rtype: C{list} 1604 1605 """ 1606 if self.client_instance and hasattr(self.client_instance, 'lang'): 1607 lang = self.client_instance.lang 1608 return self.control_session.get_published_applications(lang=lang, refresh=refresh, raw=raw, very_raw=very_raw, max_no_submenus=max_no_submenus)
1609 __get_published_applications = get_published_applications 1610
1611 - def exec_published_application(self, exec_name, timeout=20):
1612 """\ 1613 Execute an application while in published application mode. 1614 1615 @param exec_name: command to execute on server 1616 @type exec_name: C{str} 1617 1618 """ 1619 if self.terminal_session is not None: 1620 self.logger('for %s executing published application: %s' % (self.profile_name, exec_name), loglevel=log.loglevel_NOTICE) 1621 self.terminal_session.exec_published_application(exec_name, timeout=timeout, env=self.session_environment)
1622 __exec_published_application = exec_published_application 1623
1624 - def do_auto_start_or_resume(self, newest=True, oldest=False, all_suspended=False, start=True, redirect_to_client=True):
1625 """\ 1626 Automatically start or resume this session, if already associated with a server session. Otherwise 1627 resume a server-side available/suspended session (see options to declare which session to resume). 1628 If no session is available for resuming a new session will be launched. 1629 1630 Sessions in published applications mode are not resumed/started by this method. 1631 1632 @param newest: if resuming, only resume newest/youngest session 1633 @type newest: C{bool} 1634 @param oldest: if resuming, only resume oldest session 1635 @type oldest: C{bool} 1636 @param all_suspended: if resuming, resume all suspended sessions 1637 @type all_suspended: C{bool} 1638 @param start: is no session is to be resumed, start a new session 1639 @type start: C{bool} 1640 @param redirect_to_client: redirect this call to the L{X2goClient} instance (if available) to allow frontend interaction 1641 @type redirect_to_client: C{bool} 1642 1643 @return: returns success (or failure) of starting/resuming this sessions 1644 @rtype: C{bool} 1645 1646 """ 1647 if self.client_instance and redirect_to_client: 1648 return self.client_instance.session_auto_start_or_resume(self()) 1649 else: 1650 if self.session_name is not None and 'PUBLISHED' not in self.session_name: 1651 return self.resume() 1652 else: 1653 session_infos = self.list_sessions() 1654 1655 # only auto start/resume non-pubapp sessions 1656 for session_name in session_infos.keys(): 1657 if session_infos[session_name].is_published_applications_provider(): 1658 del session_infos[session_name] 1659 1660 if session_infos: 1661 if newest: 1662 return self.resume(session_name=utils.session_names_by_timestamp(session_infos)[-1]) 1663 elif oldest: 1664 return self.resume(session_name=utils.session_names_by_timestamp(session_infos)[-1]) 1665 elif all_suspended: 1666 for session_name in [ _sn for _sn in session_infos.keys() if session_infos[_sn].is_suspended() ]: 1667 return self.resume(session_name=session_name) 1668 else: 1669 if not self.published_applications: 1670 return self.start()
1671 __do_auto_start_or_resume = do_auto_start_or_resume 1672
1673 - def reset_progress_status(self):
1674 """\ 1675 Reset session startup/resumption progress status. 1676 1677 """ 1678 self._progress_status = 0
1679
1680 - def get_progress_status(self):
1681 """\ 1682 Retrieve session startup/resumption progress status. 1683 1684 @return: returns an C{int} value between 0 and 100 reflecting the session startup/resumption status 1685 @rtype: C{int} 1686 1687 """ 1688 return self._progress_status
1689
1690 - def resume(self, session_name=None, session_list=None, cmd=None, progress_event=None):
1691 """\ 1692 Resume or continue a suspended / running X2Go session on the 1693 remote X2Go server. 1694 1695 @param session_name: the server-side name of an X2Go session 1696 @type session_name: C{str} 1697 @param session_list: a session list to avoid a server-side session list query 1698 @type session_list: C{dict} 1699 @param cmd: if starting a new session, manually hand over the command to be launched in 1700 the new session 1701 @type cmd: C{str} 1702 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 1703 L{utils.ProgressStatus}. 1704 @type progress_event: C{obj} 1705 1706 @return: returns C{True} if resuming the session has been successful, C{False} otherwise 1707 @rtype: C{bool} 1708 1709 @raise Exception: any exception that occurs during published application menu retrieval is passed through 1710 1711 """ 1712 self._lock.acquire() 1713 try: 1714 _retval = self._resume(session_name=session_name, session_list=session_list, cmd=cmd, progress_event=progress_event) 1715 except: 1716 raise 1717 finally: 1718 self._lock.release() 1719 return _retval
1720
1721 - def _resume(self, session_name=None, session_list=None, cmd=None, progress_event=None):
1722 """\ 1723 Resume or continue a suspended / running X2Go session on the 1724 remote X2Go server. 1725 1726 @param session_name: the server-side name of an X2Go session 1727 @type session_name: C{str} 1728 @param session_list: a session list to avoid a server-side session list query 1729 @type session_list: C{dict} 1730 @param cmd: if starting a new session, manually hand over the command to be launched in 1731 the new session 1732 @type cmd: C{str} 1733 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 1734 L{utils.ProgressStatus}. 1735 @type progress_event: C{obj} 1736 1737 @return: returns C{True} if resuming the session has been successful, C{False} otherwise 1738 @rtype: C{bool} 1739 1740 @raise Exception: any exception that occurs during published application menu retrieval is passed through 1741 1742 """ 1743 self.terminal_session = 'PENDING' 1744 1745 # initialize a dummy event to avoid many if clauses further down in the code 1746 self.reset_progress_status() 1747 _dummy_event = threading.Event() 1748 if type(progress_event) != type(_dummy_event): 1749 progress_event = _dummy_event 1750 1751 self._progress_status = 1 1752 progress_event.set() 1753 1754 _new_session = False 1755 if self.session_name is None: 1756 self.session_name = session_name 1757 1758 self._progress_status = 2 1759 progress_event.set() 1760 1761 if self.is_alive(): 1762 1763 self._progress_status = 5 1764 progress_event.set() 1765 1766 _control = self.control_session 1767 1768 self._progress_status = 7 1769 progress_event.set() 1770 1771 # FIXME: normally this part gets called if you suspend a session that is associated to another client 1772 # we do not have a possibility to really check if SSH has released port forwarding channels or 1773 # sockets, thus we plainly have to wait a while 1774 1775 if self.is_running(): 1776 try: 1777 1778 self._suspend() 1779 1780 self._progress_status = 10 1781 progress_event.set() 1782 1783 gevent.sleep(5) 1784 1785 self._progress_status = 15 1786 progress_event.set() 1787 1788 except x2go_exceptions.X2goSessionException: 1789 pass 1790 1791 self._progress_status = 20 1792 progress_event.set() 1793 1794 try: 1795 if self.published_applications: 1796 self.published_applications_menu = gevent.spawn(self.get_published_applications) 1797 except: 1798 # FIXME: test the code to see what exceptions may occur here... 1799 1800 self._progress_status = -1 1801 progress_event.set() 1802 raise 1803 1804 if cmd is not None: 1805 self.terminal_params['cmd'] = cmd 1806 1807 self.terminal_session = _control.resume(session_name=self.session_name, 1808 session_instance=self, 1809 session_list=session_list, 1810 logger=self.logger, **self.terminal_params) 1811 1812 self._progress_status = 25 1813 progress_event.set() 1814 1815 if self.session_name is None: 1816 _new_session = True 1817 try: 1818 self.session_name = self.terminal_session.session_info.name 1819 except AttributeError: 1820 # if self.terminal_session is None, we end up with a session failure... 1821 self.HOOK_session_startup_failed() 1822 1823 self._progress_status = -1 1824 progress_event.set() 1825 1826 return False 1827 1828 self._progress_status = 30 1829 progress_event.set() 1830 1831 if self.has_terminal_session() and not self.faulty: 1832 1833 self.terminal_session.session_info_protect() 1834 1835 if self.get_session_cmd() != 'PUBLISHED': 1836 self.published_applications = False 1837 1838 self._progress_status = 40 1839 progress_event.set() 1840 1841 if self._SUPPORTED_SOUND and self.terminal_session.params.snd_system is not 'none': 1842 self.has_terminal_session() and not self.faulty and self.terminal_session.start_sound() 1843 else: 1844 self._SUPPORTED_SOUND = False 1845 1846 self._progress_status = 50 1847 progress_event.set() 1848 1849 try: 1850 if (self._SUPPORTED_PRINTING and self.printing) or \ 1851 (self._SUPPORTED_MIMEBOX and self.allow_mimebox) or \ 1852 (self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders): 1853 self.has_terminal_session() and not self.faulty and self.terminal_session.start_sshfs() 1854 except x2go_exceptions.X2goUserException, e: 1855 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 1856 self.HOOK_sshfs_not_available() 1857 self._SUPPORTED_PRINTING = False 1858 self._SUPPORTED_MIMEBOX = False 1859 self._SUPPORTED_FOLDERSHARING = False 1860 1861 self._progress_status = 60 1862 progress_event.set() 1863 1864 if self._SUPPORTED_PRINTING and self.printing: 1865 try: 1866 self.has_terminal_session() and not self.faulty and self.terminal_session.start_printing() 1867 self.has_terminal_session() and not self.faulty and self.session_environment.update({'X2GO_SPOOLDIR': self.terminal_session.get_printing_spooldir(), }) 1868 except x2go_exceptions.X2goUserException, e: 1869 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 1870 self.HOOK_printing_not_available() 1871 self._SUPPORTED_PRINTING = False 1872 1873 self._progress_status = 70 1874 progress_event.set() 1875 1876 if self._SUPPORTED_MIMEBOX and self.allow_mimebox: 1877 try: 1878 self.has_terminal_session() and not self.faulty and self.terminal_session.start_mimebox(mimebox_extensions=self.mimebox_extensions, mimebox_action=self.mimebox_action) 1879 self.has_terminal_session() and self.session_environment.update({'X2GO_MIMEBOX': self.terminal_session.get_mimebox_spooldir(), }) 1880 except x2go_exceptions.X2goUserException, e: 1881 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 1882 self.HOOK_mimebox_not_available() 1883 self._SUPPORTED_MIMEBOX = False 1884 1885 self._progress_status = 80 1886 progress_event.set() 1887 1888 # only run the session startup command if we do not resume... 1889 if _new_session: 1890 self.has_terminal_session() and self.terminal_session.run_command(env=self.session_environment) 1891 1892 self.virgin = False 1893 self.suspended = False 1894 self.running = True 1895 self.terminated = False 1896 self.faulty = False 1897 1898 self._progress_status = 90 1899 progress_event.set() 1900 1901 # if self.client_instance exists than the folder sharing is handled via the self.set_master_session() evoked by the session registry 1902 if (not self.client_instance) and \ 1903 self._SUPPORTED_FOLDERSHARING and \ 1904 self.allow_share_local_folders: 1905 gevent.spawn(self.share_all_local_folders) 1906 1907 self._progress_status = 100 1908 progress_event.set() 1909 1910 self.has_terminal_session() and self.terminal_session.session_info_unprotect() 1911 return True 1912 1913 else: 1914 self.terminal_session = None 1915 1916 self._progress_status = -1 1917 progress_event.set() 1918 1919 return False 1920 1921 else: 1922 1923 self._progress_status = -1 1924 progress_event.set() 1925 1926 self._X2goSession__disconnect() 1927 return False
1928 1929 __resume = resume 1930
1931 - def start(self, cmd=None, progress_event=None):
1932 """\ 1933 Start a new X2Go session on the remote X2Go server. 1934 1935 @param cmd: manually hand over the command that is to be launched in the new session 1936 @type cmd: C{str} 1937 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 1938 L{utils.ProgressStatus}. 1939 @type progress_event: C{obj} 1940 1941 @return: returns C{True} if starting the session has been successful, C{False} otherwise 1942 @rtype: C{bool} 1943 1944 """ 1945 self.session_name = None 1946 return self.resume(cmd=cmd, progress_event=progress_event)
1947 __start = start 1948
1949 - def share_desktop(self, desktop=None, user=None, display=None, share_mode=0, check_desktop_list=True, progress_event=None):
1950 """\ 1951 Share an already running X2Go session on the remote X2Go server locally. The shared session may be either 1952 owned by the same user or by a user that grants access to his/her desktop session by the local user. 1953 1954 @param desktop: desktop ID of a sharable desktop in format <user>@<display> 1955 @type desktop: C{str} 1956 @param user: user name and display number can be given separately, here give the 1957 name of the user who wants to share a session with you. 1958 @type user: C{str} 1959 @param display: user name and display number can be given separately, here give the 1960 number of the display that a user allows you to be shared with. 1961 @type display: C{str} 1962 @param share_mode: desktop sharing mode, 0 is VIEW-ONLY, 1 is FULL-ACCESS. 1963 @type share_mode: C{int} 1964 @param check_desktop_list: check if the given desktop is available on the X2Go server; handle with care as 1965 the server-side C{x2golistdesktops} command might block client I/O. 1966 @type check_desktop_list: C{bool} 1967 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 1968 L{utils.ProgressStatus}. 1969 @type progress_event: C{obj} 1970 1971 @return: returns C{True} if starting the session has been successful, C{False} otherwise 1972 @rtype: C{bool} 1973 1974 @raise X2goDesktopSharingException: if the given desktop ID is not an available desktop session on the remote server 1975 @raise X2goSessionException: if the available desktop session appears to be dead, in fact 1976 1977 """ 1978 self._lock.acquire() 1979 try: 1980 _retval = self._share_desktop(desktop=desktop, user=user, display=display, share_mode=share_mode, check_desktop_list=check_desktop_list, progress_event=progress_event) 1981 except: 1982 raise 1983 finally: 1984 self._lock.release() 1985 return _retval
1986
1987 - def _share_desktop(self, desktop=None, user=None, display=None, share_mode=0, check_desktop_list=True, progress_event=None):
1988 """\ 1989 Share an already running X2Go session on the remote X2Go server locally. The shared session may be either 1990 owned by the same user or by a user that grants access to his/her desktop session by the local user. 1991 1992 @param desktop: desktop ID of a sharable desktop in format <user>@<display> 1993 @type desktop: C{str} 1994 @param user: user name and display number can be given separately, here give the 1995 name of the user who wants to share a session with you. 1996 @type user: C{str} 1997 @param display: user name and display number can be given separately, here give the 1998 number of the display that a user allows you to be shared with. 1999 @type display: C{str} 2000 @param share_mode: desktop sharing mode, 0 is VIEW-ONLY, 1 is FULL-ACCESS. 2001 @type share_mode: C{int} 2002 @param check_desktop_list: check if the given desktop is available on the X2Go server; handle with care as 2003 the server-side C{x2golistdesktops} command might block client I/O. 2004 @type check_desktop_list: C{bool} 2005 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 2006 L{utils.ProgressStatus}. 2007 @type progress_event: C{obj} 2008 2009 @return: returns C{True} if starting the session has been successful, C{False} otherwise 2010 @rtype: C{bool} 2011 2012 @raise X2goDesktopSharingException: if the given desktop ID is not an available desktop session on the remote server 2013 @raise X2goSessionException: if the available desktop session appears to be dead, in fact 2014 2015 """ 2016 self.terminal_session = 'PENDING' 2017 2018 # initialize a dummy event to avoid many if clauses further down in the code 2019 self.reset_progress_status() 2020 _dummy_event = threading.Event() 2021 if type(progress_event) != type(_dummy_event): 2022 progress_event = _dummy_event 2023 2024 self._progress_status = 5 2025 progress_event.set() 2026 2027 _desktop = desktop or '%s@%s' % (user, display) 2028 if check_desktop_list: 2029 if not _desktop in self._X2goSession__list_desktops(): 2030 _orig_desktop = _desktop 2031 _desktop = '%s.0' % _desktop 2032 if not _desktop in self._X2goSession__list_desktops(): 2033 raise x2go_exceptions.X2goDesktopSharingException('No such desktop ID: %s' % _orig_desktop) 2034 2035 self._progress_status = 33 2036 progress_event.set() 2037 2038 _session_owner = _desktop.split('@')[0] 2039 2040 if self.is_alive(): 2041 if self.get_username() != _session_owner: 2042 self.logger('waiting for user ,,%s\'\' to interactively grant you access to his/her desktop session...' % _session_owner, loglevel=log.loglevel_NOTICE) 2043 self.logger('THIS MAY TAKE A WHILE!', loglevel=log.loglevel_NOTICE) 2044 2045 self._progress_status = 50 2046 progress_event.set() 2047 2048 _control = self.control_session 2049 try: 2050 self.terminal_session = _control.share_desktop(desktop=_desktop, share_mode=share_mode, 2051 logger=self.logger, **self.terminal_params) 2052 2053 self._progress_status = 80 2054 progress_event.set() 2055 2056 except ValueError: 2057 # x2gostartagent output parsing will result in a ValueError. This one we will catch 2058 # here and change it into an X2goSessionException 2059 2060 self._progress_status = -1 2061 progress_event.set() 2062 2063 raise x2go_exceptions.X2goSessionException('the session on desktop %s is seemingly dead' % _desktop) 2064 2065 self._progress_status = 90 2066 progress_event.set() 2067 2068 if self.has_terminal_session(): 2069 self.session_name = self.terminal_session.session_info.name 2070 2071 # shared desktop sessions get their startup command set by the control 2072 # session, run this pre-set command now... 2073 self.terminal_session.run_command(env=self.session_environment) 2074 2075 self.virgin = False 2076 self.suspended = False 2077 self.running = True 2078 self.terminated = False 2079 self.faulty = False 2080 2081 self._progress_status = 100 2082 progress_event.set() 2083 2084 return self.running 2085 else: 2086 self.terminal_session = None 2087 2088 self._progress_status = -1 2089 progress_event.set() 2090 2091 else: 2092 2093 self._progress_status = -1 2094 progress_event.set() 2095 2096 self._X2goSession__disconnect() 2097 2098 return False
2099 __share_desktop = share_desktop 2100
2101 - def suspend(self):
2102 """\ 2103 Suspend this X2Go session. 2104 2105 @return: returns C{True} if suspending the session has been successful, C{False} otherwise 2106 @rtype: C{bool} 2107 2108 @raise X2goSessionException: if the session could not be suspended 2109 2110 """ 2111 self._lock.acquire() 2112 try: 2113 _retval = self._suspend() 2114 except: 2115 raise 2116 finally: 2117 self._lock.release() 2118 2119 return _retval
2120
2121 - def _suspend(self):
2122 """\ 2123 Suspend this X2Go session. 2124 2125 @return: returns C{True} if suspending the session has been successful, C{False} otherwise 2126 @rtype: C{bool} 2127 2128 @raise X2goSessionException: if the session could not be suspended 2129 2130 """ 2131 if self.is_alive(): 2132 if self.has_terminal_session(): 2133 2134 self.running = False 2135 self.suspended = True 2136 self.terminated = False 2137 self.faulty = False 2138 self.active = False 2139 2140 # unmount shared folders 2141 self.unshare_all_local_folders(force_all=True) 2142 2143 self.unset_master_session() 2144 2145 if self.has_terminal_session(): 2146 if self.terminal_session.suspend(): 2147 self.session_cleanup() 2148 del self.terminal_session 2149 self.terminal_session = None 2150 return True 2151 2152 elif self.has_control_session() and self.session_name: 2153 if self.control_session.suspend(session_name=self.session_name): 2154 2155 self.running = False 2156 self.suspended = True 2157 self.terminated = False 2158 self.faulty = False 2159 self.active = False 2160 self.session_cleanup() 2161 return True 2162 2163 else: 2164 raise x2go_exceptions.X2goSessionException('cannot suspend session') 2165 2166 else: 2167 self._X2goSession__disconnect() 2168 2169 return False
2170 __suspend = suspend 2171
2172 - def terminate(self):
2173 """\ 2174 Terminate this X2Go session. 2175 2176 @return: returns C{True} if terminating the session has been successful, C{False} otherwise 2177 @rtype: C{bool} 2178 2179 @raise X2goSessionException: if the session could not be terminated 2180 2181 """ 2182 self._lock.acquire() 2183 try: 2184 _retval = self._terminate() 2185 except: 2186 raise 2187 finally: 2188 self._lock.release() 2189 2190 return _retval
2191
2192 - def _terminate(self):
2193 """\ 2194 Terminate this X2Go session. 2195 2196 @return: returns C{True} if terminating the session has been successful, C{False} otherwise 2197 @rtype: C{bool} 2198 2199 @raise X2goSessionException: if the session could not be terminated 2200 2201 """ 2202 if self.is_alive(): 2203 if self.has_terminal_session(): 2204 2205 self.running = False 2206 self.suspended = False 2207 self.terminated = True 2208 self.faulty = False 2209 self.active = False 2210 2211 # unmount shared folders 2212 self.unshare_all_local_folders(force_all=True) 2213 2214 self.unset_master_session() 2215 2216 if self.has_terminal_session(): 2217 if self.terminal_session.terminate(): 2218 self.session_cleanup() 2219 del self.terminal_session 2220 self.terminal_session = None 2221 return True 2222 2223 elif self.has_control_session() and self.session_name: 2224 if self.control_session.terminate(session_name=self.session_name): 2225 2226 self.running = False 2227 self.suspended = False 2228 self.terminated = True 2229 self.faulty = False 2230 self.active = False 2231 self.session_cleanup() 2232 return True 2233 else: 2234 raise x2go_exceptions.X2goSessionException('cannot terminate session') 2235 2236 else: 2237 self._X2goSession__disconnect() 2238 2239 return False
2240 __terminate = terminate 2241
2242 - def get_profile_name(self):
2243 """\ 2244 Retrieve the profile name of this L{X2goSession} instance. 2245 2246 @return: X2Go client profile name of the session 2247 @rtype: C{str} 2248 2249 """ 2250 return self.profile_name
2251 __get_profile_name = get_profile_name 2252
2253 - def get_profile_id(self):
2254 """\ 2255 Retrieve the profile ID of this L{X2goSession} instance. 2256 2257 @return: the session profile's id 2258 @rtype: C{str} 2259 2260 """ 2261 return self.profile_id
2262 __get_profile_id = get_profile_id 2263 2264 ### 2265 ### QUERYING INFORMATION 2266 ### 2267
2268 - def session_ok(self):
2269 """\ 2270 Test if this C{X2goSession} is 2271 in a healthy state. 2272 2273 @return: C{True} if session is ok, C{False} otherwise 2274 @rtype: C{bool} 2275 2276 """ 2277 if self.has_terminal_session(): 2278 return self.terminal_session.ok() 2279 return False
2280 __session_ok = session_ok 2281
2283 """\ 2284 Extract color depth from session name. 2285 2286 @return: the session's color depth (as found in the session name) 2287 @rtype: C{str} 2288 2289 """ 2290 return int(self.get_session_name().split('_')[2][2:])
2291 __color_depth_from_session_name = color_depth_from_session_name 2292
2293 - def is_color_depth_ok(self):
2294 """\ 2295 Check if this session will display properly with the local screen's color depth. 2296 2297 @return: C{True} if the session will display on this client screen, 2298 C{False} otherwise. If no terminal session is yet registered with this session, C{None} is returned. 2299 @rtype: C{bool} 2300 2301 """ 2302 return utils.is_color_depth_ok(depth_session=self.color_depth_from_session_name(), depth_local=utils.local_color_depth())
2303 __is_color_depth_ok = is_color_depth_ok 2304
2305 - def is_connected(self):
2306 """\ 2307 Test if the L{X2goSession}'s control session is connected to the 2308 remote X2Go server. 2309 2310 @return: C{True} if session is connected, C{False} otherwise 2311 @rtype: C{bool} 2312 2313 """ 2314 self.connected = bool(self.control_session and self.control_session.is_connected()) 2315 if not self.connected: 2316 self.running = None 2317 self.suspended = None 2318 self.terminated = None 2319 self.faulty = None 2320 return self.connected
2321 __is_connected = is_connected 2322
2323 - def is_running(self, update_status=False):
2324 """\ 2325 Test if the L{X2goSession}'s terminal session is up and running. 2326 2327 @return: C{True} if session is running, C{False} otherwise 2328 @rtype: C{bool} 2329 2330 """ 2331 if not update_status: 2332 return self.running 2333 2334 if self.is_connected(): 2335 self.running = self.control_session.is_running(self.get_session_name()) 2336 if self.running: 2337 self.suspended = False 2338 self.terminated = False 2339 self.faulty = False 2340 if self.virgin and not self.running: 2341 self.running = None 2342 return self.running
2343 __is_running = is_running 2344
2345 - def is_suspended(self, update_status=False):
2346 """\ 2347 Test if the L{X2goSession}'s terminal session is in suspended state. 2348 2349 @return: C{True} if session is suspended, C{False} otherwise 2350 @rtype: C{bool} 2351 2352 """ 2353 if not update_status: 2354 return self.suspended 2355 2356 if self.is_connected(): 2357 self.suspended = self.control_session.is_suspended(self.get_session_name()) 2358 if self.suspended: 2359 self.running = False 2360 self.terminated = False 2361 self.faulty = False 2362 if self.virgin and not self.suspended: 2363 self.suspended = None 2364 return self.suspended
2365 __is_suspended = is_suspended 2366
2367 - def has_terminated(self, update_status=False):
2368 """\ 2369 Test if the L{X2goSession}'s terminal session has terminated. 2370 2371 @return: C{True} if session has terminated, C{False} otherwise 2372 @rtype: C{bool} 2373 2374 """ 2375 if not update_status: 2376 return self.terminated 2377 2378 if self.is_connected(): 2379 self.terminated = not self.virgin and self.control_session.has_terminated(self.get_session_name()) 2380 if self.terminated: 2381 self.running = False 2382 self.suspended = False 2383 self.faulty = False 2384 if self.virgin and not self.terminated: 2385 self.terminated = None 2386 return self.terminated
2387 __has_terminated = has_terminated 2388
2390 """\ 2391 Test if the remote session allows sharing of local folders with the session. 2392 2393 @return: returns C{True} if local folder sharing is available in the remote session 2394 @rtype: C{bool} 2395 2396 """ 2397 if self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders: 2398 if self.is_connected(): 2399 return self.control_session.is_sshfs_available() 2400 else: 2401 self.logger('session is not connected, cannot share local folders now', loglevel=log.loglevel_WARN) 2402 else: 2403 self.logger('local folder sharing is disabled for this session profile', loglevel=log.loglevel_WARN) 2404 return False
2405 __is_folder_sharing_available = is_folder_sharing_available 2406
2408 2409 # remember exported folders for restoring them on session suspension/termination 2410 if self.client_instance and self.restore_shared_local_folders: 2411 _exported_folders = copy.deepcopy(self._restore_exported_folders) 2412 for folder in [ sf for sf in self.shared_folders.keys() if self.shared_folders[sf]['status'] in ('new', 'mounted') ]: 2413 _exported_folders.update({ unicode(folder): True }) 2414 for folder in _exported_folders.keys(): 2415 if folder in [ sf for sf in self.shared_folders.keys() if self.shared_folders[sf]['status'] == 'unmounted' ]: 2416 del _exported_folders[unicode(folder)] 2417 self._restore_exported_folders = _exported_folders
2418
2419 - def share_local_folder(self, local_path=None, folder_name=None, update_exported_folders=True):
2420 """\ 2421 Share a local folder with this registered X2Go session. 2422 2423 @param local_path: the full path to an existing folder on the local 2424 file system 2425 @type local_path: C{str} 2426 @param folder_name: synonymous to C{local_path} 2427 @type folder_name: C{str} 2428 @param update_exported_folders: do an update of the session profile option ,,export'' after the operation 2429 @type update_exported_folders: C{bool} 2430 2431 @return: returns C{True} if the local folder has been successfully mounted within 2432 this X2Go session 2433 @rtype: C{bool} 2434 2435 @raise X2goSessionException: if this L{X2goSession} does not have an associated terminal session 2436 2437 """ 2438 # compat for Python-X2Go (<=0.1.1.6) 2439 if folder_name: local_path=folder_name 2440 2441 local_path = unicode(local_path) 2442 2443 retval = False 2444 if self.has_terminal_session(): 2445 if self.is_folder_sharing_available() and self.is_master_session(): 2446 2447 # for the sake of non-blocking I/O: let's pretend the action has already been successful 2448 if self.shared_folders.has_key(local_path): 2449 self.shared_folders[local_path]['status'] = 'mounted' 2450 else: 2451 self.shared_folders.update({ local_path: { 'status': 'new', 'mountpoint': '', }, }) 2452 if self.terminal_session.share_local_folder(local_path=local_path): 2453 if update_exported_folders: 2454 self._update_restore_exported_folders() 2455 retval = True 2456 else: 2457 # remove local_path from folder again if the mounting process failed 2458 if self.shared_folders[local_path]['status'] == 'new': 2459 del self.shared_folders[local_path] 2460 else: 2461 self.shared_folders[local_path]['status'] = 'unmounted' 2462 2463 # disable this local folder in session profile if restoring shared folders for following sessions is activated 2464 if self.client_instance and self.restore_shared_local_folders: 2465 if local_path in self._restore_exported_folders.keys(): 2466 self._restore_exported_folders[local_path] = False 2467 2468 else: 2469 raise x2go_exceptions.X2goSessionException('this X2goSession object does not have any associated terminal') 2470 return retval
2471 2472 __share_local_folder = share_local_folder 2473
2474 - def share_all_local_folders(self, update_exported_folders=True):
2475 """\ 2476 Share all local folders configured to be mounted within this X2Go session. 2477 2478 @param update_exported_folders: do an update of the session profile option ,,export'' after the operation 2479 @type update_exported_folders: C{bool} 2480 2481 @return: returns C{True} if all local folders could be successfully mounted 2482 inside this X2Go session 2483 @rtype: C{bool} 2484 2485 """ 2486 retval = False 2487 if self.is_running() and not self.faulty and self._SUPPORTED_FOLDERSHARING and self.share_local_folders and self.allow_share_local_folders and self.has_terminal_session(): 2488 if self.is_master_session(): 2489 if self.is_folder_sharing_available(): 2490 retval = True 2491 for _folder in self.share_local_folders: 2492 try: 2493 retval = self.share_local_folder(_folder, update_exported_folders=False) and retval 2494 except x2go_exceptions.X2goUserException, e: 2495 retval = False 2496 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 2497 if update_exported_folders: 2498 self._update_restore_exported_folders() 2499 else: 2500 self.HOOK_foldersharing_not_available() 2501 return retval
2502 __share_all_local_folders = share_all_local_folders 2503
2504 - def unshare_local_folder(self, local_path=None, update_exported_folders=True):
2505 """\ 2506 Unshare a local folder that is mounted within this X2Go session. 2507 2508 @param local_path: the full path to an existing folder on the local 2509 file system that is mounted in this X2Go session and shall be 2510 unmounted 2511 @type local_path: C{str} 2512 @param update_exported_folders: do an update of the session profile option ,,export'' after the operation 2513 @type update_exported_folders: C{bool} 2514 2515 @return: returns C{True} if all local folders could be successfully unmounted 2516 inside this X2Go session 2517 @rtype: C{bool} 2518 2519 @raise X2goSessionException: if this L{X2goSession} does not have an associated terminal session 2520 2521 """ 2522 retval = False 2523 2524 local_path = unicode(local_path) 2525 2526 if self.has_terminal_session(): 2527 if self.is_folder_sharing_available() and self.is_master_session() and local_path in self.shared_folders.keys(): 2528 2529 # for the sake of non-blocking I/O: let's pretend the action has already been successful 2530 self.shared_folders[local_path]['status'] = 'unmounted' 2531 if self.terminal_session.unshare_local_folder(local_path=local_path): 2532 retval = True 2533 else: 2534 # if unmounting failed restore the status with ,,mounted'', not sure if that works ok... 2535 self.shared_folders[local_path]['status'] = 'mounted' 2536 2537 else: 2538 raise x2go_exceptions.X2goSessionException('this X2goSession object does not have any associated terminal') 2539 2540 return retval
2541 __unshare_local_folder = unshare_local_folder 2542
2543 - def unshare_all_local_folders(self, force_all=False, update_exported_folders=True):
2544 """\ 2545 Unshare all local folders mounted within this X2Go session. 2546 2547 @param force_all: Really unmount _all_ shared folders, including the print spool folder and 2548 the MIME box spool dir (not recommended). 2549 @type force_all: C{bool} 2550 @param update_exported_folders: do an update of the session profile option ,,export'' after the operation 2551 @type update_exported_folders: C{bool} 2552 2553 @return: returns C{True} if all local folders could be successfully unmounted 2554 inside this X2Go session 2555 @rtype: C{bool} 2556 2557 @raise X2goSessionException: if this L{X2goSession} does not have an associated terminal session 2558 2559 """ 2560 if self.has_terminal_session(): 2561 if self.is_folder_sharing_available() and self.is_master_session(): 2562 2563 if force_all: 2564 retval = self.terminal_session.unshare_all_local_folders() 2565 if retval: 2566 self.shared_folders = {} 2567 return retval 2568 else: 2569 retval = True 2570 _shared_folders = copy.deepcopy(self.shared_folders) 2571 for _folder in _shared_folders.keys(): 2572 retval = self.unshare_local_folder(_folder, update_exported_folders=False) and retval 2573 if update_exported_folders: 2574 self._update_restore_exported_folders() 2575 return retval 2576 else: 2577 raise x2go_exceptions.X2goSessionException('this X2goSession object does not have any associated terminal') 2578 return False
2579 __unshare_all_local_folders = unshare_all_local_folders 2580
2581 - def get_shared_folders(self, check_list_mounts=False, mounts=None):
2582 """\ 2583 Get a list of local folders mounted within this X2Go session from this client. 2584 2585 @param check_list_mounts: if set to C{True} the list of shared folders is referenced against 2586 the latest status of the server-side mount list. 2587 @type check_list_mounts: C{bool} 2588 @param mounts: a server-side dictionary of session name keys and lists of mounted shares (server-side mount points) 2589 @type mounts: C{dict} 2590 2591 @return: returns a C{list} of those local folder names that are mounted with this X2Go session. 2592 @rtype: C{list} 2593 2594 """ 2595 if self.is_folder_sharing_available and self.is_master_session() and self.shared_folders and check_list_mounts: 2596 2597 unshared_folders = [] 2598 if mounts is None: 2599 mounts = self.list_mounts() 2600 _defacto_mounts = [ unicode(m.split('|')[1].split('/')[-1]) for m in mounts ] 2601 2602 for shared_folder in self.shared_folders.keys(): 2603 2604 if _X2GOCLIENT_OS == 'Windows': 2605 _driveletter, _path = os.path.splitdrive(shared_folder) 2606 _mount_point = '_windrive_%s%s' % (_driveletter[0], _path.replace('\\', '_')) 2607 _mount_point = _mount_point.replace(' ', '_') 2608 2609 else: 2610 _mount_point = shared_folder.replace('/', '_') 2611 _mount_point = _mount_point.replace(' ', '_') 2612 2613 self.shared_folders[shared_folder]['status'] = 'mounted' 2614 self.shared_folders[shared_folder]['mountpoint'] = unicode(_mount_point) 2615 2616 for m in _defacto_mounts: 2617 for sf in self.shared_folders.keys(): 2618 if self.shared_folders[sf]['mountpoint'] == m: 2619 self.shared_folders[sf]['status'] = 'mounted' 2620 break 2621 2622 unshared_folders = False 2623 2624 for sf in self.shared_folders.keys(): 2625 m = self.shared_folders[sf]['mountpoint'] 2626 if m and m not in _defacto_mounts: 2627 try: 2628 if self.shared_folders[sf]['status'] == 'mounted': 2629 self.shared_folders[sf]['status'] = 'unmounted' 2630 self.logger('Detected server-side unsharing of client-side folder for profile %s: %s:' % (self.get_profile_name(), sf), loglevel=log.loglevel_INFO) 2631 unshared_folders = True 2632 except IndexError: 2633 pass 2634 2635 if unshared_folders: 2636 self._update_restore_exported_folders() 2637 2638 return [ unicode(sf) for sf in self.shared_folders if self.shared_folders[sf]['status'] in ('new', 'mounted') ]
2639 __get_shared_folders = get_shared_folders 2640
2641 - def is_locked(self):
2642 """\ 2643 Query session if it is locked by some command being processed. 2644 2645 @return: returns C{True} is the session is locked, C{False} if not; returns C{None}, if there is no 2646 control session yet. 2647 @rtype: C{bool} 2648 2649 """ 2650 if self.control_session is not None: 2651 return self.control_session.locked or self.locked 2652 return None
2653 __is_locked = is_locked 2654
2655 - def session_cleanup(self):
2656 """\ 2657 Clean up X2Go session. 2658 2659 """ 2660 # release terminal session's proxy 2661 if self.has_terminal_session(): 2662 self.terminal_session.release_proxy() 2663 2664 # remove client-side session cache 2665 if self.terminated and self.has_terminal_session(): 2666 self.terminal_session.post_terminate_cleanup() 2667 2668 # destroy terminal session 2669 if self.has_terminal_session(): 2670 self.terminal_session.__del__() 2671 2672 self.terminal_session = None
2673 __session_cleanup = session_cleanup
2674