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

Source Code for Module x2go.session

   1  # -*- coding: utf-8 -*- 
   2   
   3  # Copyright (C) 2010-2013 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_list_desktops_timeout(self):
471 """\ 472 HOOK method: called if the x2golistdesktops command generates a timeout due to long execution time. 473 474 """ 475 if self.client_instance: 476 self.client_instance.HOOK_list_desktops_timeout(profile_name=self.profile_name) 477 else: 478 self.logger('HOOK_list_desktops_timeout: the server-side x2golistdesktops command for session profile %s took too long to return results. This can happen from time to time, please try again.' % self.profile_name, loglevel=log.loglevel_WARN)
479
480 - def HOOK_no_such_desktop(self, desktop='UNKNOWN'):
481 """\ 482 HOOK method: called if it is tried to connect to a shared desktop that's not available (anymore). 483 484 """ 485 if self.client_instance: 486 self.client_instance.HOOK_no_such_desktop(profile_name=self.profile_name, desktop=desktop) 487 else: 488 self.logger('HOOK_no_such_desktop: the desktop %s (via session profile %s) is not available for sharing (anymore).' % (desktop, self.profile_name), loglevel=log.loglevel_WARN)
489
490 - def HOOK_rforward_request_denied(self, server_port=0):
491 """\ 492 HOOK method: called if a reverse port forwarding request has been denied. 493 494 @param server_port: remote server port (starting point of reverse forwarding tunnel) 495 @type server_port: C{str} 496 497 """ 498 if self.client_instance: 499 self.client_instance.HOOK_rforward_request_denied(profile_name=self.profile_name, session_name=self.session_name, server_port=server_port) 500 else: 501 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)
502
503 - def HOOK_forwarding_tunnel_setup_failed(self, chain_host='UNKNOWN', chain_port=0):
504 """\ 505 HOOK method: called if a port forwarding tunnel setup failed. 506 507 @param chain_host: hostname of chain host (forwarding tunnel end point) 508 @type chain_host: C{str} 509 @param chain_port: port of chain host (forwarding tunnel end point) 510 @type chain_port: C{str} 511 512 """ 513 # mark session as faulty 514 self.faulty = True 515 516 if self.client_instance: 517 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) 518 else: 519 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) 520 521 # get rid of the faulty session... 522 try: 523 self._terminate() 524 except x2go_exceptions.X2GoSessionException: 525 pass
526
528 """\ 529 HOOK method: called if X2Go client-side printing is not available. 530 531 """ 532 if self.client_instance: 533 self.client_instance.HOOK_printing_not_available(profile_name=self.profile_name, session_name=self.session_name) 534 else: 535 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)
536
537 - def HOOK_mimebox_not_available(self):
538 """\ 539 HOOK method: called if the X2Go MIME box is not available. 540 541 """ 542 if self.client_instance: 543 self.client_instance.HOOK_mimebox_not_available(profile_name=self.profile_name, session_name=self.session_name) 544 else: 545 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)
546
548 """\ 549 HOOK method: called if X2Go client-side folder-sharing is not available. 550 551 """ 552 if self.client_instance: 553 self.client_instance.HOOK_foldersharing_not_available(profile_name=self.profile_name, session_name=self.session_name) 554 else: 555 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)
556
557 - def HOOK_sshfs_not_available(self):
558 """\ 559 HOOK method: called if the X2Go server denies SSHFS access. 560 561 """ 562 if self.client_instance: 563 self.client_instance.HOOK_sshfs_not_available(profile_name=self.profile_name, session_name=self.session_name) 564 else: 565 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)
566
567 - def HOOK_check_host_dialog(self, host, port, fingerprint='no fingerprint', fingerprint_type='UNKNOWN'):
568 """\ 569 HOOK method: called if a host check is requested. This hook has to either return C{True} (default) or C{False}. 570 571 @param host: SSH server name to validate 572 @type host: C{str} 573 @param port: SSH server port to validate 574 @type port: C{int} 575 @param fingerprint: the server's fingerprint 576 @type fingerprint: C{str} 577 @param fingerprint_type: finger print type (like RSA, DSA, ...) 578 @type fingerprint_type: C{str} 579 @return: if host validity is verified, this hook method should return C{True} 580 @rtype: C{bool} 581 582 """ 583 if self.client_instance: 584 return self.client_instance.HOOK_check_host_dialog(profile_name=self.profile_name, host=host, port=port, fingerprint=fingerprint, fingerprint_type=fingerprint_type) 585 else: 586 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) 587 return True
588
589 - def init_control_session(self):
590 """\ 591 Initialize a new control session (C{X2GoControlSession*}). 592 593 """ 594 low_latency = self.terminal_params.has_key('link') and self.terminal_params['link'].lower() in ('modem', 'isdn') 595 596 if self.control_session is None: 597 self.logger('initializing X2GoControlSession', loglevel=log.loglevel_DEBUG) 598 self.control_session = self.control_backend(profile_name=self.profile_name, 599 add_to_known_hosts=self.add_to_known_hosts, 600 known_hosts=self.known_hosts, 601 forward_sshagent=self.forward_sshagent, 602 terminal_backend=self.terminal_backend, 603 info_backend=self.info_backend, 604 list_backend=self.list_backend, 605 proxy_backend=self.proxy_backend, 606 client_rootdir=self.client_rootdir, 607 sessions_rootdir=self.sessions_rootdir, 608 ssh_rootdir=self.ssh_rootdir, 609 low_latency=low_latency, 610 logger=self.logger) 611 else: 612 self.control_session.low_latency = low_latency
613 __init_control_session = init_control_session 614
615 - def is_master_session(self):
616 """\ 617 Is this session a/the master session of sessions. 618 619 The master session is the session has been launched first for a specific connection, 620 it also is _the_ session that controls the client-side shared folders. 621 622 If this L{X2GoSession} instance is a standalone instance (without parent L{X2GoClient}) 623 this method will always return C{True}. 624 625 @return: returns C{True} if this session is a master session 626 @rtype: C{bool} 627 628 """ 629 if self.master_session is None and self.client_instance is None: 630 return True 631 return bool(self.master_session)
632 __is_master_session = is_master_session 633
634 - def set_master_session(self, wait=0, max_wait=20):
635 """\ 636 Declare this as a master session of a connection channel. 637 638 This method gets called by the L{X2GoSessionRegistry} while sessions are starting or resuming and it relies on 639 an already set-up terminal session. 640 641 @param wait: wait for <wait> seconds before sharing local folders via the new master session 642 of the corresponding session profile. 643 @type wait: C{int} 644 @param max_wait: wait for <max_wait> seconds for the terminal session to appear 645 @type max_wait: C{int} 646 647 """ 648 self.logger('Using session %s as master session for profile %s.' % (self.get_session_name(), self.get_profile_name()), loglevel=log.loglevel_NOTICE) 649 self.master_session = True 650 651 # retrieve an up-to-date list of sharable local folders from the client instance 652 if self.client_instance: 653 _exports = self.client_instance.get_profile_config(self.profile_name, 'export') 654 self.share_local_folders = [ sf for sf in _exports.keys() if _exports[sf] ] 655 656 i = 0 657 while i < max_wait: 658 i += 1 659 if self.has_terminal_session(): 660 break 661 gevent.sleep(1) 662 663 if wait: 664 gevent.spawn_later(wait, self.share_all_local_folders, update_exported_folders=False) 665 else: 666 gevent.spawn(self.share_all_local_folders, update_exported_folders=False)
667 __set_master_session = set_master_session 668
669 - def unset_master_session(self):
670 """\ 671 Declare this as a non-master session of a connection channel. 672 673 """ 674 # unmount shared folders 675 if self.has_terminal_session(): 676 self.unshare_all_local_folders(update_exported_folders=False) 677 self.master_session = False
678 __unset_master_session = unset_master_session 679
680 - def set_server(self, server):
681 """\ 682 Modify server name after L{X2GoSession} has already been initialized. 683 684 @param server: new server name 685 @type server: C{str} 686 687 """ 688 self.server = server
689 __set_server = set_server 690
691 - def set_port(self, port):
692 """\ 693 Modify server port after L{X2GoSession} has already been initialized. 694 695 @param port: socket port of server to connect to 696 @type port: C{int} 697 698 """ 699 self.port = port
700 __set_port = set_port 701
702 - def set_profile_name(self, profile_name):
703 """\ 704 Modify session profile name after L{X2GoSession} has already been initialized. 705 706 @param profile_name: new session profile name 707 @type profile_name: C{str} 708 709 """ 710 self.profile_name = profile_name 711 self.control_session.set_profile_name(profile_name)
712 __set_profile_name = set_profile_name 713
714 - def get_session_profile_option(self, option):
715 """\ 716 Retrieve a specific profile parameter for this session. 717 718 @param option: name of a specific profile option to be queried. 719 @type option: C{str} 720 721 @return: value for profile option C{<option>} 722 @rtype: C{bool,str,int} 723 724 @raise X2GoProfileException: if the session profile option is unknown 725 726 """ 727 if option in _X2GO_SESSION_PARAMS + _X2GO_TERMINAL_PARAMS + _X2GO_SSHPROXY_PARAMS and hasattr(self, option): 728 return eval("self.%s" % option) 729 else: 730 raise x2go_exceptions.X2GoProfileException('Unknown session profile option: %s.' % option)
731 __get_session_profile_option = get_session_profile_option 732
733 - def update_params(self, params):
734 """\ 735 This method can be used to modify L{X2GoSession} parameters after the 736 L{X2GoSession} instance has already been initialized. 737 738 @param params: a Python dictionary with L{X2GoSession} parameters 739 @type params: C{dict} 740 741 """ 742 try: del params['server'] 743 except KeyError: pass 744 try: del params['profile_name'] 745 except KeyError: pass 746 try: del params['profile_id'] 747 except KeyError: pass 748 try: 749 self.printing = params['printing'] 750 del params['printing'] 751 except KeyError: pass 752 try: 753 self.allow_share_local_folders = params['allow_share_local_folders'] 754 del params['allow_share_local_folders'] 755 except KeyError: pass 756 try: 757 self.share_local_folders = params['share_local_folders'] 758 del params['share_local_folders'] 759 except KeyError: pass 760 try: 761 self.restore_shared_local_folders = params['restore_shared_local_folders'] 762 del params['restore_shared_local_folders'] 763 except KeyError: pass 764 try: 765 self.allow_mimebox = params['allow_mimebox'] 766 del params['allow_mimebox'] 767 except KeyError: pass 768 try: 769 self.mimebox_extensions = params['mimebox_extensions'] 770 del params['mimebox_extensions'] 771 except KeyError: pass 772 try: 773 self.mimebox_action = params['mimebox_action'] 774 del params['mimebox_action'] 775 except KeyError: pass 776 try: 777 self.use_sshproxy = params['use_sshproxy'] 778 del params['use_sshproxy'] 779 except KeyError: pass 780 try: 781 self.sshproxy_reuse_authinfo = params['sshproxy_reuse_authinfo'] 782 del params['sshproxy_reuse_authinfo'] 783 except KeyError: pass 784 try: 785 self.auto_connect = params['auto_connect'] 786 del params['auto_connect'] 787 except KeyError: pass 788 try: 789 self.forward_sshagent = params['forward_sshagent'] 790 del params['forward_sshagent'] 791 except KeyError: pass 792 try: 793 self.auto_start_or_resume = params['auto_start_or_resume'] 794 del params['auto_start_or_resume'] 795 except KeyError: pass 796 797 if self.sshproxy_reuse_authinfo: 798 if params.has_key('key_filename'): 799 params['sshproxy_key_filename'] = params['key_filename'] 800 if params.has_key('pkey'): 801 params['sshproxy_pkey'] = params['pkey'] 802 if params.has_key('password'): 803 params['sshproxy_password'] = params['password'] 804 805 _terminal_params = copy.deepcopy(params) 806 _control_params = copy.deepcopy(params) 807 _sshproxy_params = copy.deepcopy(params) 808 for p in params.keys(): 809 if p in session._X2GO_TERMINAL_PARAMS: 810 del _control_params[p] 811 del _sshproxy_params[p] 812 elif p in session._X2GO_SSHPROXY_PARAMS: 813 del _control_params[p] 814 del _terminal_params[p] 815 else: 816 del _sshproxy_params[p] 817 del _terminal_params[p] 818 819 self.control_params.update(_control_params) 820 self.terminal_params.update(_terminal_params) 821 self.sshproxy_params.update(_sshproxy_params)
822
823 - def get_uuid(self):
824 """\ 825 Retrieve session UUID hash for this L{X2GoSession}. 826 827 @return: the session's UUID hash 828 @rtype: C{str} 829 830 """ 831 return str(self.uuid)
832 __get_uuid = get_uuid 833
834 - def get_username(self):
835 """\ 836 After a session has been set up you can query the 837 username the session runs as. 838 839 @return: the remote username the X2Go session runs as 840 @rtype: C{str} 841 842 """ 843 # try to retrieve the username from the control session, if already connected 844 try: 845 return self.control_session.get_transport().get_username() 846 except AttributeError: 847 return self.control_params['username']
848 __get_username = get_username 849
850 - def user_is_x2gouser(self, username=None):
851 """\ 852 Check if a given user is valid server-side X2Go user. 853 854 @param username: username to check validity for 855 @type username: C{str} 856 857 @return: C{True} if the username is allowed to launch X2Go sessions 858 @rtype: C{bool} 859 860 """ 861 if username is None: 862 username = self.__get_username() 863 return self.control_session.is_x2gouser(username)
864 __user_is_x2gouser = user_is_x2gouser 865
866 - def get_password(self):
867 """\ 868 After a session has been setup up you can query the 869 username's password from the session. 870 871 @return: the username's password 872 @rtype: C{str} 873 874 """ 875 return self.control_session._session_password
876 __get_password = get_password 877
878 - def get_server_peername(self):
879 """\ 880 After a session has been setup up you can query the 881 peername of the host this session is connected to (or 882 about to connect to). 883 884 @return: the address of the server the X2Go session is 885 connected to (as an C{(addr,port)} tuple) 886 @rtype: C{tuple} 887 888 """ 889 return self.control_session.remote_peername()
890 __get_server_peername = get_server_peername 891 remote_peername = get_server_peername 892 __remote_peername = get_server_peername 893
894 - def get_server_hostname(self):
895 """\ 896 After a session has been setup up you can query the 897 hostname of the host this session is connected to (or 898 about to connect to). 899 900 @return: the hostname of the server the X2Go session is 901 connected to / about to connect to 902 @rtype: C{str} 903 904 """ 905 self.server = self.control_session.get_hostname() 906 return self.server
907 __get_server_hostname = get_server_hostname 908
909 - def get_server_port(self):
910 """\ 911 After a session has been setup up you can query the 912 IP socket port used for connecting the remote X2Go server. 913 914 @return: the server-side IP socket port that is used by the X2Go session to 915 connect to the server 916 @rtype: C{str} 917 918 """ 919 return self.control_session.get_port()
920 __get_server_port = get_server_port 921
922 - def get_session_name(self):
923 """\ 924 Retrieve the server-side X2Go session name for this session. 925 926 @return: X2Go session name 927 @rtype: C{str} 928 929 """ 930 return self.session_name
931 __get_session_name = get_session_name 932
933 - def set_session_name(self, session_name):
934 """\ 935 Manipulate the L{X2GoSession}'s session name. 936 937 @param session_name: the new session name to be set 938 @type session_name: C{str} 939 940 """ 941 self.session_name = session_name
942 __set_session_name = set_session_name 943
944 - def get_session_info(self):
945 """\ 946 Retrieve the server-side X2Go session info object for this session. 947 948 @return: X2Go session info 949 @rtype: C{obj} 950 951 """ 952 if self.has_terminal_session(): 953 self.terminal_session.get_session_info()
954 __get_session_info = get_session_info 955
956 - def get_session_cmd(self):
957 """\ 958 Retrieve the server-side command that is used to start a session 959 on the remote X2Go server. 960 961 @return: server-side session command 962 @rtype: C{str} 963 964 """ 965 if self.has_terminal_session(): 966 return self.terminal_session.get_session_cmd() 967 if self.terminal_params.has_key('cmd'): 968 return self.terminal_params['cmd'] 969 return None
970 __get_session_cmd = get_session_cmd 971
972 - def get_session_type(self):
973 """\ 974 Retrieve the session type of a session (R, D, S or P). 975 976 - R: rootless session 977 - D: desktop session 978 - S: shadow session 979 - P: session in published applications mode 980 981 @return: session type 982 @rtype: C{str} 983 984 """ 985 if self.has_terminal_session(): 986 return self.terminal_session.get_session_type() 987 else: 988 return None
989 __get_session_type = get_session_type 990
991 - def get_session_title(self):
992 """\ 993 Retrieve the session window title of this 994 session. 995 996 @return: session window title 997 @rtype: C{str} 998 999 """ 1000 if self.has_terminal_session(): 1001 return self.terminal_session.session_title 1002 else: 1003 return 'X2GO-%s' % self.get_session_name()
1004 __get_session_title = get_session_title 1005
1006 - def get_control_session(self):
1007 """\ 1008 Retrieve the control session (C{X2GoControlSession*} backend) of this L{X2GoSession}. 1009 1010 @return: the L{X2GoSession}'s control session 1011 @rtype: C{X2GoControlSession*} instance 1012 1013 """ 1014 return self.control_session
1015 __get_control_session = get_control_session 1016
1017 - def has_control_session(self):
1018 """\ 1019 Check if this L{X2GoSession} instance has an associated control session. 1020 1021 @return: returns C{True} if this L{X2GoSession} has a control session associated to itself 1022 @rtype: C{bool} 1023 1024 """ 1025 return self.control_session is not None
1026 __has_control_session = has_control_session 1027
1028 - def get_terminal_session(self):
1029 """\ 1030 Retrieve the terminal session (C{X2GoTerminalSession*} backend) of this L{X2GoSession}. 1031 1032 @return: the L{X2GoSession}'s terminal session 1033 @rtype: C{X2GoControlTerminal*} instance 1034 1035 """ 1036 if self.terminal_session == 'PENDING': 1037 return None 1038 return self.terminal_session
1039 __get_terminal_session = get_terminal_session 1040
1041 - def has_terminal_session(self):
1042 """\ 1043 Check if this L{X2GoSession} instance has an associated terminal session. 1044 1045 @return: returns C{True} if this L{X2GoSession} has a terminal session associated to itself 1046 @rtype: C{bool} 1047 1048 """ 1049 return self.terminal_session not in (None, 'PENDING')
1050 __has_terminal_session = has_terminal_session 1051 is_associated = has_terminal_session 1052 __is_associated = has_terminal_session 1053
1054 - def check_host(self):
1055 """\ 1056 Provide a host check mechanism. This method basically calls the L{HOOK_check_host_dialog()} method 1057 which by itself calls the L{X2GoClient.HOOK_check_host_dialog()} method. Make sure you 1058 override any of these to enable user interaction on X2Go server validity checks. 1059 1060 @return: returns C{True} if an X2Go server host is valid for authentication 1061 @rtype: C{bool} 1062 1063 """ 1064 if self.connected: 1065 return True 1066 1067 _port = self.control_params['port'] 1068 (_valid, _host, _port, _fingerprint, _fingerprint_type) = self.control_session.check_host(self.server, port=_port) 1069 return _valid or self.HOOK_check_host_dialog(host=_host, port=_port, fingerprint=_fingerprint, fingerprint_type=_fingerprint_type)
1070 __check_host = check_host 1071
1072 - def uses_sshproxy(self):
1073 """\ 1074 Check if a session is configured to use an intermediate SSH proxy server. 1075 1076 @return: returns C{True} if the session is configured to use an SSH proxy, C{False} otherwise. 1077 @rtype: C{bool} 1078 1079 """ 1080 return self.use_sshproxy
1081 __uses_sshproxy = uses_sshproxy 1082
1083 - def reuses_sshproxy_authinfo(self):
1084 """\ 1085 Check if a session is configured to re-use the X2Go session's password / key for 1086 proxy authentication, as well. 1087 1088 @return: returns C{True} if the session is configured to re-use session password / key for proxy authentication 1089 @rtype: C{bool} 1090 1091 """ 1092 return self.sshproxy_reuse_authinfo
1093 __reuses_sshproxy_authinfo = reuses_sshproxy_authinfo 1094
1095 - def can_sshproxy_auto_connect(self):
1096 """\ 1097 Check if a session's SSH proxy (if used) is configured adequately to be able to auto-connect 1098 to the SSH proxy server (e.g. by public key authentication). 1099 1100 @return: returns C{True} if the session's SSH proxy can auto-connect, C{False} otherwise, C{None} 1101 if no SSH proxy is used for this session, C{None} is returned. 1102 @rtype: C{bool} 1103 1104 """ 1105 if self.use_sshproxy: 1106 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'])): 1107 return True 1108 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'])): 1109 return True 1110 elif self.sshproxy_params.has_key('sshproxy_pkey') and self.sshproxy_params['sshproxy_pkey']: 1111 return True 1112 elif self.sshproxy_reuse_authinfo and self.control_params.has_key('pkey') and self.control_params['pkey']: 1113 return True 1114 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'))): 1115 return True 1116 elif self.sshproxy_params.has_key('sshproxy_allow_agent') and self.sshproxy_params['sshproxy_allow_agent'] and paramiko.Agent().get_keys(): 1117 return True 1118 else: 1119 return False 1120 else: 1121 return None
1122 __can_sshproxy_auto_connect = can_sshproxy_auto_connect 1123
1124 - def can_auto_connect(self):
1125 """\ 1126 Check if a session is configured adequately to be able to auto-connect to the X2Go 1127 server (e.g. public key authentication). 1128 1129 @return: returns C{True} if the session can auto-connect, C{False} otherwise, C{None} 1130 if no control session has been set up yet. 1131 @rtype: C{bool} 1132 1133 """ 1134 if self.control_session is None: 1135 return None 1136 1137 _can_sshproxy_auto_connect = self.can_sshproxy_auto_connect() 1138 1139 # do we have a key file passed as control parameter? 1140 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'])): 1141 return (_can_sshproxy_auto_connect is None) or _can_sshproxy_auto_connect 1142 1143 # or a private key? 1144 elif self.control_params.has_key('pkey') and self.control_params['pkey']: 1145 return (_can_sshproxy_auto_connect is None) or _can_sshproxy_auto_connect 1146 1147 # or a key auto discovery? 1148 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'))): 1149 return (_can_sshproxy_auto_connect is None) or _can_sshproxy_auto_connect 1150 1151 # or an SSH agent usage? 1152 elif self.control_params.has_key('allow_agent') and self.control_params['allow_agent'] and paramiko.Agent().get_keys(): 1153 return (_can_sshproxy_auto_connect is None) or _can_sshproxy_auto_connect 1154 1155 else: 1156 return False
1157 __can_auto_connect = can_auto_connect 1158
1159 - def do_auto_connect(self, redirect_to_client=True):
1160 """\ 1161 Automatically connect this session. 1162 1163 @return: Return success (or failure) of connecting this sessions 1164 @rtype: C{bool} 1165 1166 """ 1167 if not self.is_connected(): 1168 if self.client_instance and redirect_to_client: 1169 return self.client_instance.session_auto_connect(self()) 1170 else: 1171 if self.can_auto_connect() and self.auto_connect: 1172 gevent.spawn(self.connect) 1173 elif self.auto_connect: 1174 gevent.spawn(self.HOOK_auto_connect)
1175 __do_auto_connect = do_auto_connect 1176
1177 - def connect(self, username='', password='', add_to_known_hosts=False, force_password_auth=False, 1178 look_for_keys=None, allow_agent=None, 1179 use_sshproxy=None, sshproxy_reuse_authinfo=False, sshproxy_user='', sshproxy_password='', sshproxy_force_password_auth=False):
1180 """\ 1181 Connects to the L{X2GoSession}'s server host. This method basically wraps around 1182 the C{X2GoControlSession*.connect()} method. 1183 1184 @param username: the username for the X2Go server that is going to be 1185 connected to (as a last minute way of changing the session username) 1186 @type username: C{str} 1187 @param password: the user's password for the X2Go server that is going to be 1188 connected to 1189 @type password: C{str} 1190 @param add_to_known_hosts: non-paramiko option, if C{True} paramiko.AutoAddPolicy() 1191 is used as missing-host-key-policy. If set to C{False} paramiko.RejectPolicy() 1192 is used 1193 @type add_to_known_hosts: C{bool} 1194 @param force_password_auth: disable SSH pub/priv key authentication mechanisms 1195 completely 1196 @type force_password_auth: C{bool} 1197 @param look_for_keys: set to C{True} to enable searching for discoverable 1198 private key files in C{~/.ssh/} 1199 @type look_for_keys: C{bool} 1200 @param allow_agent: set to C{True} to enable connecting to a local SSH agent 1201 for acquiring authentication information 1202 @type allow_agent: C{bool} 1203 @param use_sshproxy: use an SSH proxy host for connecting the target X2Go server 1204 @type use_sshproxy: C{bool} 1205 @param sshproxy_reuse_authinfo: for proxy authentication re-use the X2Go session's password / key file 1206 @type sshproxy_reuse_authinfo: C{bool} 1207 @param sshproxy_user: username for authentication against the SSH proxy host 1208 @type sshproxy_user: C{str} 1209 @param sshproxy_password: password for authentication against the SSH proxy host 1210 @type sshproxy_password: C{str} 1211 @param sshproxy_force_password_auth: enforce password authentication even is a key(file) is present 1212 @type sshproxy_force_password_auth: C{bool} 1213 1214 @return: returns C{True} is the connection to the X2Go server has been successful 1215 @rtype C{bool} 1216 1217 @raise X2GoSessionException: on control session exceptions 1218 @raise X2GoRemoteHomeException: if the remote home directory does not exist 1219 @raise Exception: any other exception during connecting is passed through 1220 1221 """ 1222 if self.control_session and self.control_session.is_connected(): 1223 self.logger('control session is already connected, skipping authentication', loglevel=log.loglevel_DEBUG) 1224 self.connected = True 1225 else: 1226 1227 if use_sshproxy is not None: 1228 self.use_sshproxy = use_sshproxy 1229 1230 if sshproxy_reuse_authinfo is not None: 1231 self.sshproxy_reuse_authinfo = sshproxy_reuse_authinfo 1232 1233 if username: 1234 self.control_params['username'] = username 1235 if add_to_known_hosts is not None: 1236 self.control_params['add_to_known_hosts'] = add_to_known_hosts 1237 if force_password_auth is not None: 1238 self.control_params['force_password_auth'] = force_password_auth 1239 if look_for_keys is not None: 1240 self.control_params['look_for_keys'] = look_for_keys 1241 if allow_agent is not None: 1242 self.control_params['allow_agent'] = allow_agent 1243 1244 if sshproxy_user: 1245 self.sshproxy_params['sshproxy_user'] = sshproxy_user 1246 if sshproxy_password: 1247 self.sshproxy_params['sshproxy_password'] = sshproxy_password 1248 if sshproxy_force_password_auth: 1249 self.sshproxy_params['sshproxy_force_password_auth'] = sshproxy_force_password_auth 1250 1251 self.control_params['password'] = password 1252 1253 if self.sshproxy_reuse_authinfo: 1254 if self.control_params.has_key('key_filename'): 1255 self.sshproxy_params['sshproxy_key_filename'] = self.control_params['key_filename'] 1256 if self.control_params.has_key('pkey'): 1257 self.sshproxy_params['sshproxy_pkey'] = self.control_params['pkey'] 1258 if self.control_params.has_key('password'): 1259 self.sshproxy_params['sshproxy_password'] = self.control_params['password'] 1260 1261 _params = {} 1262 _params.update(self.control_params) 1263 _params.update(self.sshproxy_params) 1264 1265 if 'port' not in _params: 1266 _params['port'] = self.port 1267 1268 try: 1269 self.connected = self.control_session.connect(self.server, 1270 use_sshproxy=self.use_sshproxy, 1271 session_instance=self, 1272 forward_sshagent=self.forward_sshagent, 1273 **_params) 1274 except x2go_exceptions.X2GoControlSessionException, e: 1275 raise x2go_exceptions.X2GoSessionException(str(e)) 1276 except x2go_exceptions.X2GoRemoteHomeException, e: 1277 self.disconnect() 1278 raise e 1279 except: 1280 # remove credentials immediately 1281 self.control_params['password'] = '' 1282 if self.sshproxy_params and self.sshproxy_params.has_key('sshproxy_password'): 1283 del self.sshproxy_params['sshproxy_password'] 1284 raise 1285 finally: 1286 # remove credentials immediately 1287 self.control_params['password'] = '' 1288 if self.sshproxy_params and self.sshproxy_params.has_key('sshproxy_password'): 1289 del self.sshproxy_params['sshproxy_password'] 1290 1291 if not self.connected: 1292 # then tidy up... 1293 self.disconnect() 1294 1295 self.get_server_hostname() 1296 1297 if self.connected: 1298 self.update_status() 1299 self.retrieve_server_features() 1300 if self.auto_start_or_resume: 1301 gevent.spawn(self.do_auto_start_or_resume) 1302 1303 return self.connected
1304 __connect = connect 1305
1306 - def disconnect(self):
1307 """\ 1308 Disconnect this L{X2GoSession} instance. 1309 1310 @return: returns C{True} if the disconnect operation has been successful 1311 @rtype: C{bool} 1312 1313 """ 1314 self.connected = False 1315 self.running = None 1316 self.suspended = None 1317 self.terminated = None 1318 self.faults = None 1319 self.active = False 1320 self._lock.release() 1321 self.unset_master_session() 1322 try: 1323 self.update_status(force_update=True) 1324 except x2go_exceptions.X2GoControlSessionException: 1325 pass 1326 retval = self.control_session.disconnect() 1327 return retval
1328 __disconnect = disconnect 1329
1330 - def retrieve_server_features(self):
1331 """\ 1332 Query the X2Go server for a list of supported features. 1333 1334 """ 1335 self.server_features = self.control_session.query_server_features()
1336 __retrieve_server_features = retrieve_server_features 1337
1338 - def get_server_features(self):
1339 """\ 1340 Return a list of X2Go server-sides features (supported functionalities). 1341 1342 @return: a C{list} of X2Go feature names 1343 @rtype: C{list} 1344 1345 """ 1346 return self.server_features
1347 __get_server_features = get_server_features 1348
1349 - def has_server_feature(self, feature):
1350 """\ 1351 Check if C{feature} is a present feature of the connected X2Go server. 1352 1353 @param feature: an X2Go server feature as found in C{$SHAREDIR/x2go/feature.d/*} 1354 @type feature: C{str} 1355 1356 @return: returns C{True} if the feature is present 1357 @rtype: C{bool} 1358 1359 """ 1360 return feature in self.get_server_features()
1361 __has_server_feature = has_server_feature 1362
1363 - def set_session_window_title(self, title=''):
1364 """\ 1365 Modify session window title. If the session ID does not occur in the 1366 given title, it will be prepended, so that every X2Go session window 1367 always contains the X2Go session ID of that window. 1368 1369 @param title: new title for session window 1370 @type title: C{str} 1371 1372 """ 1373 if self.terminal_session is not None: 1374 self.terminal_session.set_session_window_title(title=title)
1375 __set_session_window_title = set_session_window_title 1376
1377 - def raise_session_window(self):
1378 """\ 1379 Try to lift the session window above all other windows and bring 1380 it to focus. 1381 1382 """ 1383 if self.terminal_session is not None: 1384 self.terminal_session.raise_session_window()
1385 __raise_session_window = raise_session_window 1386
1387 - def set_print_action(self, print_action, **kwargs):
1388 """\ 1389 If X2Go client-side printing is enable within this X2Go session you can use 1390 this method to alter the way how incoming print spool jobs are handled/processed. 1391 1392 For further information, please refer to the documentation of the L{X2GoClient.set_session_print_action()} 1393 method. 1394 1395 @param print_action: one of the named above print actions, either as string or class instance 1396 @type print_action: C{str} or C{instance} 1397 @param kwargs: additional information for the given print action (print 1398 action arguments), for possible print action arguments and their values see each individual 1399 print action class 1400 @type kwargs: C{dict} 1401 1402 """ 1403 if type(print_action) is not types.StringType: 1404 return False 1405 self.terminal_session.set_print_action(print_action, **kwargs)
1406 __set_print_action = set_print_action 1407
1408 - def is_alive(self):
1409 """\ 1410 Find out if this X2Go session is still alive (that is: connected to the server). 1411 1412 @return: returns C{True} if the server connection is still alive 1413 @rtype: C{bool} 1414 1415 """ 1416 self.connected = self.control_session.is_alive() 1417 if self.control_session.has_session_died(): 1418 self.HOOK_on_control_session_death() 1419 if not self.connected: 1420 self._X2GoSession__disconnect() 1421 return self.connected
1422 __is_alive = is_alive 1423
1424 - def clean_sessions(self, destroy_terminals=True, published_applications=False):
1425 """\ 1426 Clean all running sessions for the authenticated user on the remote X2Go server. 1427 1428 @param destroy_terminals: destroy associated terminal sessions 1429 @type destroy_terminals: C{bool} 1430 @param published_applications: clean sessions that are published applications providers, too 1431 @type published_applications: C{bool} 1432 1433 """ 1434 if self.is_alive(): 1435 1436 # unmount shared folders 1437 if self.has_terminal_session(): 1438 self.unshare_all_local_folders(force_all=True) 1439 1440 self.control_session.clean_sessions(destroy_terminals=destroy_terminals, published_applications=published_applications) 1441 else: 1442 self._X2GoSession__disconnect()
1443 __clean_sessions = clean_sessions 1444
1445 - def list_sessions(self, raw=False):
1446 """\ 1447 List all sessions on the remote X2Go server that are owned by the authenticated user 1448 1449 @param raw: if C{True} the output of this method equals 1450 the output of the server-side C{x2golistsessions} command 1451 @type raw: C{bool} 1452 1453 @return: a session list (as data object or list of strings when called with C{raw=True} option) 1454 @rtype: C{X2GoServerSessionList*} instance or C{list} 1455 1456 """ 1457 try: 1458 return self.control_session.list_sessions(raw=raw) 1459 except x2go_exceptions.X2GoControlSessionException: 1460 if self.connected: self.HOOK_on_control_session_death() 1461 self._X2GoSession__disconnect() 1462 return None
1463 __list_sessions = list_sessions 1464
1465 - def list_desktops(self, raw=False):
1466 """\ 1467 List X2Go desktops sessions available for desktop sharing on the remote X2Go server. 1468 1469 @param raw: if C{True} the output of this method equals 1470 the output of the server-side C{x2golistdesktops} command 1471 @type raw: C{bool} 1472 1473 @return: a list of strings representing available desktop sessions 1474 @rtype: C{list} 1475 1476 """ 1477 try: 1478 return self.control_session.list_desktops(raw=raw) 1479 except x2go_exceptions.X2GoTimeoutException: 1480 if self.is_alive(): self.HOOK_list_desktop_timeout() 1481 return [] 1482 except x2go_exceptions.X2GoControlSessionException: 1483 if self.connected: self.HOOK_on_control_session_death() 1484 self._X2GoSession__disconnect() 1485 return None
1486 __list_desktops = list_desktops 1487
1488 - def list_mounts(self, raw=False):
1489 """\ 1490 Use the X2Go session registered under C{session_uuid} to 1491 retrieve its list of mounted client shares for that session. 1492 1493 @param raw: output the list of mounted client shares in X2Go's 1494 raw C{x2golistmounts} format 1495 @type raw: C{bool} 1496 1497 @return: a list of strings representing mounted client shares for this session 1498 @rtype: C{list} 1499 1500 """ 1501 try: 1502 return self.control_session.list_mounts(self.session_name, raw=raw) 1503 except x2go_exceptions.X2GoControlSessionException: 1504 if self.connected: self.HOOK_on_control_session_death() 1505 self._X2GoSession__disconnect() 1506 return None
1507 __list_mounts = list_mounts 1508
1509 - def update_status(self, session_list=None, force_update=False):
1510 """\ 1511 Update the current session status. The L{X2GoSession} instance uses an internal 1512 session status cache that allows to query the session status without the need 1513 of retrieving data from the remote X2Go server for each query. 1514 1515 The session status (if initialized properly with the L{X2GoClient} constructor gets 1516 updated in regularly intervals. 1517 1518 In case you use the L{X2GoSession} class in standalone instances (that is: without 1519 being embedded into an L{X2GoSession} context) then run this method in regular 1520 intervals to make sure the L{X2GoSession}'s internal status cache information 1521 is always up-to-date. 1522 1523 @param session_list: provide an C{X2GoServerSessionList*} that refers to X2Go sessions we want to update. 1524 This option is mainly for reducing server/client traffic. 1525 @type session_list: C{X2GoServerSessionList*} instance 1526 @param force_update: force a session status update, if if the last update is less then 1 second ago 1527 @type force_update: C{bool} 1528 1529 @raise Exception: any exception is passed through in case the session disconnected surprisingly 1530 or has been marked as faulty 1531 1532 """ 1533 if not force_update and self._last_status is not None: 1534 _status_update_timedelta = time.time() - self._last_status['timestamp'] 1535 1536 # skip this session status update if not longer than a second ago... 1537 if _status_update_timedelta < 1: 1538 self.logger('status update interval too short (%s), skipping status update this time...' % _status_update_timedelta, loglevel=log.loglevel_DEBUG) 1539 return False 1540 1541 e = None 1542 self._last_status = copy.deepcopy(self._current_status) 1543 if session_list is None: 1544 try: 1545 session_list = self.control_session.list_sessions() 1546 self.connected = True 1547 except x2go_exceptions.X2GoControlSessionException, e: 1548 self.connected = False 1549 self.running = None 1550 self.suspended = None 1551 self.terminated = None 1552 self.faulty = None 1553 1554 if self.connected: 1555 try: 1556 _session_name = self.get_session_name() 1557 _session_info = session_list[_session_name] 1558 self.running = _session_info.is_running() 1559 self.suspended = _session_info.is_suspended() 1560 if not self.virgin: 1561 self.terminated = not (self.running or self.suspended) 1562 else: 1563 self.terminated = None 1564 except KeyError, e: 1565 self.running = False 1566 self.suspended = False 1567 if not self.virgin: 1568 self.terminated = True 1569 self.faulty = not (self.running or self.suspended or self.terminated or self.virgin) 1570 1571 self._current_status = { 1572 'timestamp': time.time(), 1573 'server': self.server, 1574 'virgin': self.virgin, 1575 'connected': self.connected, 1576 'running': self.running, 1577 'suspended': self.suspended, 1578 'terminated': self.terminated, 1579 'faulty': self.faulty, 1580 } 1581 1582 if (not self.connected or self.faulty) and e: 1583 raise e 1584 1585 return True
1586 __update_status = update_status 1587
1589 """\ 1590 Returns true if this session runs in published applications mode. 1591 1592 @return: returns C{True} if this session is a provider session for published applications. 1593 @rtype: C{bool} 1594 1595 """ 1596 if self.has_terminal_session() and self.is_running() : 1597 return self.terminal_session.is_published_applications_provider() 1598 return False
1599 __is_published_applications_provider = is_published_applications_provider 1600
1601 - def get_published_applications(self, lang=None, refresh=False, raw=False, very_raw=False, max_no_submenus=defaults.PUBAPP_MAX_NO_SUBMENUS):
1602 """\ 1603 Return a list of published menu items from the X2Go server 1604 for session type published applications. 1605 1606 @param lang: locale/language identifier 1607 @type lang: C{str} 1608 @param refresh: force reload of the menu tree from X2Go server 1609 @type refresh: C{bool} 1610 @param raw: retrieve a raw output of the server list of published applications 1611 @type raw: C{bool} 1612 @param very_raw: retrieve a very raw output of the server list of published applications (as-is output of x2gogetapps script) 1613 @type very_raw: C{bool} 1614 1615 @return: A C{list} of C{dict} elements. Each C{dict} elements has a 1616 C{desktop} key containing the text output of a .desktop file and 1617 an C{icon} key which contains the desktop icon data base64 encoded 1618 @rtype: C{list} 1619 1620 """ 1621 if self.client_instance and hasattr(self.client_instance, 'lang'): 1622 lang = self.client_instance.lang 1623 return self.control_session.get_published_applications(lang=lang, refresh=refresh, raw=raw, very_raw=very_raw, max_no_submenus=max_no_submenus)
1624 __get_published_applications = get_published_applications 1625
1626 - def exec_published_application(self, exec_name, timeout=20):
1627 """\ 1628 Execute an application while in published application mode. 1629 1630 @param exec_name: command to execute on server 1631 @type exec_name: C{str} 1632 1633 """ 1634 if self.terminal_session is not None: 1635 self.logger('for %s executing published application: %s' % (self.profile_name, exec_name), loglevel=log.loglevel_NOTICE) 1636 self.terminal_session.exec_published_application(exec_name, timeout=timeout, env=self.session_environment)
1637 __exec_published_application = exec_published_application 1638
1639 - def do_auto_start_or_resume(self, newest=True, oldest=False, all_suspended=False, start=True, redirect_to_client=True):
1640 """\ 1641 Automatically start or resume this session, if already associated with a server session. Otherwise 1642 resume a server-side available/suspended session (see options to declare which session to resume). 1643 If no session is available for resuming a new session will be launched. 1644 1645 Sessions in published applications mode are not resumed/started by this method. 1646 1647 @param newest: if resuming, only resume newest/youngest session 1648 @type newest: C{bool} 1649 @param oldest: if resuming, only resume oldest session 1650 @type oldest: C{bool} 1651 @param all_suspended: if resuming, resume all suspended sessions 1652 @type all_suspended: C{bool} 1653 @param start: is no session is to be resumed, start a new session 1654 @type start: C{bool} 1655 @param redirect_to_client: redirect this call to the L{X2GoClient} instance (if available) to allow frontend interaction 1656 @type redirect_to_client: C{bool} 1657 1658 @return: returns success (or failure) of starting/resuming this sessions 1659 @rtype: C{bool} 1660 1661 """ 1662 if self.client_instance and redirect_to_client: 1663 return self.client_instance.session_auto_start_or_resume(self()) 1664 else: 1665 if self.session_name is not None and 'PUBLISHED' not in self.session_name: 1666 return self.resume() 1667 else: 1668 session_infos = self.list_sessions() 1669 1670 # only auto start/resume non-pubapp sessions 1671 for session_name in session_infos.keys(): 1672 if session_infos[session_name].is_published_applications_provider(): 1673 del session_infos[session_name] 1674 1675 if session_infos: 1676 sorted_session_names = utils.session_names_by_timestamp(session_infos) 1677 if newest: 1678 if sorted_session_names[0].find('RDP') == -1: 1679 return self.resume(session_name=sorted_session_names[-1]) 1680 elif oldest: 1681 if sorted_session_names[-1].find('RDP') == -1: 1682 return self.resume(session_name=sorted_session_names[0]) 1683 elif all_suspended: 1684 for session_name in [ _sn for _sn in session_infos.keys() if session_infos[_sn].is_suspended() ]: 1685 return self.resume(session_name=session_name) 1686 else: 1687 if not self.published_applications: 1688 return self.start()
1689 __do_auto_start_or_resume = do_auto_start_or_resume 1690
1691 - def reset_progress_status(self):
1692 """\ 1693 Reset session startup/resumption progress status. 1694 1695 """ 1696 self._progress_status = 0
1697
1698 - def get_progress_status(self):
1699 """\ 1700 Retrieve session startup/resumption progress status. 1701 1702 @return: returns an C{int} value between 0 and 100 reflecting the session startup/resumption status 1703 @rtype: C{int} 1704 1705 """ 1706 return self._progress_status
1707
1708 - def resume(self, session_name=None, session_list=None, cmd=None, progress_event=None):
1709 """\ 1710 Resume or continue a suspended / running X2Go session on the 1711 remote X2Go server. 1712 1713 @param session_name: the server-side name of an X2Go session 1714 @type session_name: C{str} 1715 @param session_list: a session list to avoid a server-side session list query 1716 @type session_list: C{dict} 1717 @param cmd: if starting a new session, manually hand over the command to be launched in 1718 the new session 1719 @type cmd: C{str} 1720 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 1721 L{utils.ProgressStatus}. 1722 @type progress_event: C{obj} 1723 1724 @return: returns C{True} if resuming the session has been successful, C{False} otherwise 1725 @rtype: C{bool} 1726 1727 @raise Exception: any exception that occurs during published application menu retrieval is passed through 1728 1729 """ 1730 self._lock.acquire() 1731 try: 1732 _retval = self._resume(session_name=session_name, session_list=session_list, cmd=cmd, progress_event=progress_event) 1733 except: 1734 raise 1735 finally: 1736 self._lock.release() 1737 return _retval
1738
1739 - def _resume(self, session_name=None, session_list=None, cmd=None, progress_event=None):
1740 """\ 1741 Resume or continue a suspended / running X2Go session on the 1742 remote X2Go server. 1743 1744 @param session_name: the server-side name of an X2Go session 1745 @type session_name: C{str} 1746 @param session_list: a session list to avoid a server-side session list query 1747 @type session_list: C{dict} 1748 @param cmd: if starting a new session, manually hand over the command to be launched in 1749 the new session 1750 @type cmd: C{str} 1751 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 1752 L{utils.ProgressStatus}. 1753 @type progress_event: C{obj} 1754 1755 @return: returns C{True} if resuming the session has been successful, C{False} otherwise 1756 @rtype: C{bool} 1757 1758 @raise Exception: any exception that occurs during published application menu retrieval is passed through 1759 1760 """ 1761 self.terminal_session = 'PENDING' 1762 1763 # initialize a dummy event to avoid many if clauses further down in the code 1764 self.reset_progress_status() 1765 _dummy_event = threading.Event() 1766 if type(progress_event) != type(_dummy_event): 1767 progress_event = _dummy_event 1768 1769 self._progress_status = 1 1770 progress_event.set() 1771 1772 _new_session = False 1773 if self.session_name is None: 1774 self.session_name = session_name 1775 1776 self._progress_status = 2 1777 progress_event.set() 1778 1779 if self.is_alive(): 1780 1781 self._progress_status = 5 1782 progress_event.set() 1783 1784 _control = self.control_session 1785 1786 self._progress_status = 7 1787 progress_event.set() 1788 1789 # FIXME: normally this part gets called if you suspend a session that is associated to another client 1790 # we do not have a possibility to really check if SSH has released port forwarding channels or 1791 # sockets, thus we plainly have to wait a while 1792 1793 if self.is_running(): 1794 try: 1795 1796 self._suspend() 1797 1798 self._progress_status = 10 1799 progress_event.set() 1800 1801 gevent.sleep(5) 1802 1803 self._progress_status = 15 1804 progress_event.set() 1805 1806 except x2go_exceptions.X2GoSessionException: 1807 pass 1808 1809 self._progress_status = 20 1810 progress_event.set() 1811 1812 try: 1813 if self.published_applications: 1814 self.published_applications_menu = gevent.spawn(self.get_published_applications) 1815 except: 1816 # FIXME: test the code to see what exceptions may occur here... 1817 1818 self._progress_status = -1 1819 progress_event.set() 1820 raise 1821 1822 if cmd is not None: 1823 self.terminal_params['cmd'] = cmd 1824 1825 self.terminal_session = _control.resume(session_name=self.session_name, 1826 session_instance=self, 1827 session_list=session_list, 1828 logger=self.logger, **self.terminal_params) 1829 1830 self._progress_status = 25 1831 progress_event.set() 1832 1833 if self.session_name is None: 1834 _new_session = True 1835 try: 1836 self.session_name = self.terminal_session.session_info.name 1837 except AttributeError: 1838 # if self.terminal_session is None, we end up with a session failure... 1839 self.HOOK_session_startup_failed() 1840 1841 self._progress_status = -1 1842 progress_event.set() 1843 1844 return False 1845 1846 self._progress_status = 30 1847 progress_event.set() 1848 1849 if self.has_terminal_session() and not self.faulty: 1850 1851 self.terminal_session.session_info_protect() 1852 1853 if self.get_session_cmd() != 'PUBLISHED': 1854 self.published_applications = False 1855 1856 self._progress_status = 40 1857 progress_event.set() 1858 1859 if self._SUPPORTED_SOUND and self.terminal_session.params.snd_system is not 'none': 1860 self.has_terminal_session() and not self.faulty and self.terminal_session.start_sound() 1861 else: 1862 self._SUPPORTED_SOUND = False 1863 1864 self._progress_status = 50 1865 progress_event.set() 1866 1867 try: 1868 if (self._SUPPORTED_PRINTING and self.printing) or \ 1869 (self._SUPPORTED_MIMEBOX and self.allow_mimebox) or \ 1870 (self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders): 1871 self.has_terminal_session() and not self.faulty and self.terminal_session.start_sshfs() 1872 except x2go_exceptions.X2GoUserException, e: 1873 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 1874 self.HOOK_sshfs_not_available() 1875 self._SUPPORTED_PRINTING = False 1876 self._SUPPORTED_MIMEBOX = False 1877 self._SUPPORTED_FOLDERSHARING = False 1878 1879 self._progress_status = 60 1880 progress_event.set() 1881 1882 if self._SUPPORTED_PRINTING and self.printing: 1883 try: 1884 self.has_terminal_session() and not self.faulty and self.terminal_session.start_printing() 1885 self.has_terminal_session() and not self.faulty and self.session_environment.update({'X2GO_SPOOLDIR': self.terminal_session.get_printing_spooldir(), }) 1886 except x2go_exceptions.X2GoUserException, e: 1887 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 1888 self.HOOK_printing_not_available() 1889 self._SUPPORTED_PRINTING = False 1890 1891 self._progress_status = 70 1892 progress_event.set() 1893 1894 if self._SUPPORTED_MIMEBOX and self.allow_mimebox: 1895 try: 1896 self.has_terminal_session() and not self.faulty and self.terminal_session.start_mimebox(mimebox_extensions=self.mimebox_extensions, mimebox_action=self.mimebox_action) 1897 self.has_terminal_session() and self.session_environment.update({'X2GO_MIMEBOX': self.terminal_session.get_mimebox_spooldir(), }) 1898 except x2go_exceptions.X2GoUserException, e: 1899 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 1900 self.HOOK_mimebox_not_available() 1901 self._SUPPORTED_MIMEBOX = False 1902 1903 self._progress_status = 80 1904 progress_event.set() 1905 1906 # only run the session startup command if we do not resume... 1907 if _new_session: 1908 self.has_terminal_session() and self.terminal_session.run_command(env=self.session_environment) 1909 1910 self.virgin = False 1911 self.suspended = False 1912 self.running = True 1913 self.terminated = False 1914 self.faulty = False 1915 1916 self._progress_status = 90 1917 progress_event.set() 1918 1919 # if self.client_instance exists than the folder sharing is handled via the self.set_master_session() evoked by the session registry 1920 if (not self.client_instance) and \ 1921 self._SUPPORTED_FOLDERSHARING and \ 1922 self.allow_share_local_folders: 1923 gevent.spawn(self.share_all_local_folders) 1924 1925 self._progress_status = 100 1926 progress_event.set() 1927 1928 self.has_terminal_session() and self.terminal_session.session_info_unprotect() 1929 return True 1930 1931 else: 1932 self.terminal_session = None 1933 1934 self._progress_status = -1 1935 progress_event.set() 1936 1937 return False 1938 1939 else: 1940 1941 self._progress_status = -1 1942 progress_event.set() 1943 1944 self._X2GoSession__disconnect() 1945 return False
1946 __resume = resume 1947
1948 - def start(self, cmd=None, progress_event=None):
1949 """\ 1950 Start a new X2Go session on the remote X2Go server. 1951 1952 @param cmd: manually hand over the command that is to be launched in the new session 1953 @type cmd: C{str} 1954 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 1955 L{utils.ProgressStatus}. 1956 @type progress_event: C{obj} 1957 1958 @return: returns C{True} if starting the session has been successful, C{False} otherwise 1959 @rtype: C{bool} 1960 1961 """ 1962 self.session_name = None 1963 return self.resume(cmd=cmd, progress_event=progress_event)
1964 __start = start 1965
1966 - def share_desktop(self, desktop=None, user=None, display=None, share_mode=0, check_desktop_list=True, progress_event=None):
1967 """\ 1968 Share an already running X2Go session on the remote X2Go server locally. The shared session may be either 1969 owned by the same user or by a user that grants access to his/her desktop session by the local user. 1970 1971 @param desktop: desktop ID of a sharable desktop in format <user>@<display> 1972 @type desktop: C{str} 1973 @param user: user name and display number can be given separately, here give the 1974 name of the user who wants to share a session with you. 1975 @type user: C{str} 1976 @param display: user name and display number can be given separately, here give the 1977 number of the display that a user allows you to be shared with. 1978 @type display: C{str} 1979 @param share_mode: desktop sharing mode, 0 is VIEW-ONLY, 1 is FULL-ACCESS. 1980 @type share_mode: C{int} 1981 @param check_desktop_list: check if the given desktop is available on the X2Go server; handle with care as 1982 the server-side C{x2golistdesktops} command might block client I/O. 1983 @type check_desktop_list: C{bool} 1984 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 1985 L{utils.ProgressStatus}. 1986 @type progress_event: C{obj} 1987 1988 @return: returns C{True} if starting the session has been successful, C{False} otherwise 1989 @rtype: C{bool} 1990 1991 @raise X2GoDesktopSharingException: if the given desktop ID is not an available desktop session on the remote server 1992 @raise X2GoSessionException: if the available desktop session appears to be dead, in fact 1993 1994 """ 1995 self._lock.acquire() 1996 try: 1997 _retval = self._share_desktop(desktop=desktop, user=user, display=display, share_mode=share_mode, check_desktop_list=check_desktop_list, progress_event=progress_event) 1998 except: 1999 raise 2000 finally: 2001 self._lock.release() 2002 return _retval
2003
2004 - def _share_desktop(self, desktop=None, user=None, display=None, share_mode=0, check_desktop_list=True, progress_event=None):
2005 """\ 2006 Share an already running X2Go session on the remote X2Go server locally. The shared session may be either 2007 owned by the same user or by a user that grants access to his/her desktop session by the local user. 2008 2009 @param desktop: desktop ID of a sharable desktop in format <user>@<display> 2010 @type desktop: C{str} 2011 @param user: user name and display number can be given separately, here give the 2012 name of the user who wants to share a session with you. 2013 @type user: C{str} 2014 @param display: user name and display number can be given separately, here give the 2015 number of the display that a user allows you to be shared with. 2016 @type display: C{str} 2017 @param share_mode: desktop sharing mode, 0 is VIEW-ONLY, 1 is FULL-ACCESS. 2018 @type share_mode: C{int} 2019 @param check_desktop_list: check if the given desktop is available on the X2Go server; handle with care as 2020 the server-side C{x2golistdesktops} command might block client I/O. 2021 @type check_desktop_list: C{bool} 2022 @param progress_event: a C{thread.Event} object that notifies a status object like the one in 2023 L{utils.ProgressStatus}. 2024 @type progress_event: C{obj} 2025 2026 @return: returns C{True} if starting the session has been successful, C{False} otherwise 2027 @rtype: C{bool} 2028 2029 @raise X2GoDesktopSharingException: if the given desktop ID is not an available desktop session on the remote server 2030 @raise X2GoSessionException: if the available desktop session appears to be dead, in fact 2031 2032 """ 2033 self.terminal_session = 'PENDING' 2034 2035 # initialize a dummy event to avoid many if clauses further down in the code 2036 self.reset_progress_status() 2037 _dummy_event = threading.Event() 2038 if type(progress_event) != type(_dummy_event): 2039 progress_event = _dummy_event 2040 2041 self._progress_status = 5 2042 progress_event.set() 2043 2044 _desktop = desktop or '%s@%s' % (user, display) 2045 if check_desktop_list: 2046 desktop_list = self._X2GoSession__list_desktops() 2047 if not _desktop in desktop_list: 2048 _orig_desktop = _desktop 2049 _desktop = '%s.0' % _desktop 2050 if not _desktop in desktop_list: 2051 self.HOOK_no_such_desktop(desktop=_orig_desktop) 2052 self._progress_status = -1 2053 progress_event.set() 2054 return False 2055 2056 self._progress_status = 33 2057 progress_event.set() 2058 2059 _session_owner = _desktop.split('@')[0] 2060 2061 if self.is_alive(): 2062 if self.get_username() != _session_owner: 2063 self.logger('waiting for user ,,%s\'\' to interactively grant you access to his/her desktop session...' % _session_owner, loglevel=log.loglevel_NOTICE) 2064 self.logger('THIS MAY TAKE A WHILE!', loglevel=log.loglevel_NOTICE) 2065 2066 self._progress_status = 50 2067 progress_event.set() 2068 2069 _control = self.control_session 2070 try: 2071 self.terminal_session = _control.share_desktop(desktop=_desktop, share_mode=share_mode, 2072 logger=self.logger, **self.terminal_params) 2073 2074 self._progress_status = 80 2075 progress_event.set() 2076 2077 except ValueError: 2078 # x2gostartagent output parsing will result in a ValueError. This one we will catch 2079 # here and change it into an X2GoSessionException 2080 2081 self._progress_status = -1 2082 progress_event.set() 2083 2084 raise x2go_exceptions.X2GoSessionException('the session on desktop %s is seemingly dead' % _desktop) 2085 2086 self._progress_status = 90 2087 progress_event.set() 2088 2089 if self.has_terminal_session(): 2090 self.session_name = self.terminal_session.session_info.name 2091 2092 # shared desktop sessions get their startup command set by the control 2093 # session, run this pre-set command now... 2094 self.terminal_session.run_command(env=self.session_environment) 2095 2096 self.virgin = False 2097 self.suspended = False 2098 self.running = True 2099 self.terminated = False 2100 self.faulty = False 2101 2102 self._progress_status = 100 2103 progress_event.set() 2104 2105 return self.running 2106 else: 2107 self.terminal_session = None 2108 2109 self._progress_status = -1 2110 progress_event.set() 2111 2112 else: 2113 2114 self._progress_status = -1 2115 progress_event.set() 2116 2117 self._X2GoSession__disconnect() 2118 2119 return False
2120 __share_desktop = share_desktop 2121
2122 - def is_desktop_session(self):
2123 """\ 2124 Test if this X2Go session is a desktop session. 2125 2126 @return: C{True} if this session is of session type desktop ('D'). 2127 @rtype: C{bool} 2128 2129 """ 2130 if self.has_terminal_session(): 2131 return self.terminal_session.is_desktop_session()
2132 __is_desktop_session = is_desktop_session 2133
2134 - def is_rootless_session(self):
2135 """\ 2136 Test if this X2Go session is a rootless session. 2137 2138 @return: C{True} if this session is of session type rootless ('R'). 2139 @rtype: C{bool} 2140 2141 """ 2142 if self.has_terminal_session(): 2143 return self.terminal_session.is_rootless_session()
2144 __is_rootless_session = is_rootless_session 2145
2146 - def is_shadow_session(self):
2147 """\ 2148 Test if this X2Go session is a desktop sharing (aka shadow) session. 2149 2150 @return: C{True} if this session is of session type shadow ('S'). 2151 @rtype: C{bool} 2152 2153 """ 2154 if self.has_terminal_session(): 2155 return self.terminal_session.is_shadow_session()
2156 __is_shadow_session = is_shadow_session 2157
2158 - def is_pubapp_session(self):
2159 """\ 2160 Test if this X2Go session is a published applications session. 2161 2162 @return: C{True} if this session is of session type published applications ('P'). 2163 @rtype: C{bool} 2164 2165 """ 2166 if self.has_terminal_session(): 2167 return self.terminal_session.is_pubapp_session()
2168 __is_pubapp_session = is_pubapp_session 2169
2170 - def suspend(self):
2171 """\ 2172 Suspend this X2Go session. 2173 2174 @return: returns C{True} if suspending the session has been successful, C{False} otherwise 2175 @rtype: C{bool} 2176 2177 @raise X2GoSessionException: if the session could not be suspended 2178 2179 """ 2180 self._lock.acquire() 2181 try: 2182 _retval = self._suspend() 2183 except: 2184 raise 2185 finally: 2186 self._lock.release() 2187 2188 return _retval
2189
2190 - def _suspend(self):
2191 """\ 2192 Suspend this X2Go session. 2193 2194 @return: returns C{True} if suspending the session has been successful, C{False} otherwise 2195 @rtype: C{bool} 2196 2197 @raise X2GoSessionException: if the session could not be suspended 2198 2199 """ 2200 if self.is_alive(): 2201 if self.has_terminal_session(): 2202 2203 self.running = False 2204 self.suspended = True 2205 self.terminated = False 2206 self.faulty = False 2207 self.active = False 2208 2209 # unmount shared folders 2210 self.unshare_all_local_folders(force_all=True) 2211 2212 self.unset_master_session() 2213 2214 if self.has_terminal_session(): 2215 if self.terminal_session.suspend(): 2216 self.session_cleanup() 2217 del self.terminal_session 2218 self.terminal_session = None 2219 return True 2220 2221 elif self.has_control_session() and self.session_name: 2222 if self.control_session.suspend(session_name=self.session_name): 2223 2224 self.running = False 2225 self.suspended = True 2226 self.terminated = False 2227 self.faulty = False 2228 self.active = False 2229 self.session_cleanup() 2230 return True 2231 2232 else: 2233 raise x2go_exceptions.X2GoSessionException('cannot suspend session') 2234 2235 else: 2236 self._X2GoSession__disconnect() 2237 2238 return False
2239 __suspend = suspend 2240
2241 - def terminate(self):
2242 """\ 2243 Terminate this X2Go session. 2244 2245 @return: returns C{True} if terminating the session has been successful, C{False} otherwise 2246 @rtype: C{bool} 2247 2248 @raise X2GoSessionException: if the session could not be terminated 2249 2250 """ 2251 self._lock.acquire() 2252 try: 2253 _retval = self._terminate() 2254 except: 2255 raise 2256 finally: 2257 self._lock.release() 2258 2259 return _retval
2260
2261 - def _terminate(self):
2262 """\ 2263 Terminate this X2Go session. 2264 2265 @return: returns C{True} if terminating the session has been successful, C{False} otherwise 2266 @rtype: C{bool} 2267 2268 @raise X2GoSessionException: if the session could not be terminated 2269 2270 """ 2271 if self.is_alive(): 2272 if self.has_terminal_session(): 2273 2274 self.running = False 2275 self.suspended = False 2276 self.terminated = True 2277 self.faulty = False 2278 self.active = False 2279 2280 # unmount shared folders 2281 self.unshare_all_local_folders(force_all=True) 2282 2283 self.unset_master_session() 2284 2285 if self.has_terminal_session(): 2286 if self.terminal_session.terminate(): 2287 self.session_cleanup() 2288 del self.terminal_session 2289 self.terminal_session = None 2290 return True 2291 2292 elif self.has_control_session() and self.session_name: 2293 if self.control_session.terminate(session_name=self.session_name): 2294 2295 self.running = False 2296 self.suspended = False 2297 self.terminated = True 2298 self.faulty = False 2299 self.active = False 2300 self.session_cleanup() 2301 return True 2302 else: 2303 raise x2go_exceptions.X2GoSessionException('cannot terminate session') 2304 2305 else: 2306 self._X2GoSession__disconnect() 2307 2308 return False
2309 __terminate = terminate 2310
2311 - def get_profile_name(self):
2312 """\ 2313 Retrieve the profile name of this L{X2GoSession} instance. 2314 2315 @return: X2Go client profile name of the session 2316 @rtype: C{str} 2317 2318 """ 2319 return self.profile_name
2320 __get_profile_name = get_profile_name 2321
2322 - def get_profile_id(self):
2323 """\ 2324 Retrieve the profile ID of this L{X2GoSession} instance. 2325 2326 @return: the session profile's id 2327 @rtype: C{str} 2328 2329 """ 2330 return self.profile_id
2331 __get_profile_id = get_profile_id 2332 2333 ### 2334 ### QUERYING INFORMATION 2335 ### 2336
2337 - def session_ok(self):
2338 """\ 2339 Test if this C{X2GoSession} is 2340 in a healthy state. 2341 2342 @return: C{True} if session is ok, C{False} otherwise 2343 @rtype: C{bool} 2344 2345 """ 2346 if self.has_terminal_session(): 2347 return self.terminal_session.ok() 2348 return False
2349 __session_ok = session_ok 2350
2352 """\ 2353 Extract color depth from session name. 2354 2355 @return: the session's color depth (as found in the session name) 2356 @rtype: C{str} 2357 2358 """ 2359 return int(self.get_session_name().split('_')[2][2:])
2360 __color_depth_from_session_name = color_depth_from_session_name 2361
2362 - def is_color_depth_ok(self):
2363 """\ 2364 Check if this session will display properly with the local screen's color depth. 2365 2366 @return: C{True} if the session will display on this client screen, 2367 C{False} otherwise. If no terminal session is yet registered with this session, C{None} is returned. 2368 @rtype: C{bool} 2369 2370 """ 2371 return utils.is_color_depth_ok(depth_session=self.color_depth_from_session_name(), depth_local=utils.local_color_depth())
2372 __is_color_depth_ok = is_color_depth_ok 2373
2374 - def is_connected(self):
2375 """\ 2376 Test if the L{X2GoSession}'s control session is connected to the 2377 remote X2Go server. 2378 2379 @return: C{True} if session is connected, C{False} otherwise 2380 @rtype: C{bool} 2381 2382 """ 2383 self.connected = bool(self.control_session and self.control_session.is_connected()) 2384 if not self.connected: 2385 self.running = None 2386 self.suspended = None 2387 self.terminated = None 2388 self.faulty = None 2389 return self.connected
2390 __is_connected = is_connected 2391
2392 - def is_running(self, update_status=False):
2393 """\ 2394 Test if the L{X2GoSession}'s terminal session is up and running. 2395 2396 @return: C{True} if session is running, C{False} otherwise 2397 @rtype: C{bool} 2398 2399 """ 2400 if not update_status: 2401 return self.running 2402 2403 if self.is_connected(): 2404 self.running = self.control_session.is_running(self.get_session_name()) 2405 if self.running: 2406 self.suspended = False 2407 self.terminated = False 2408 self.faulty = False 2409 if self.virgin and not self.running: 2410 self.running = None 2411 return self.running
2412 __is_running = is_running 2413
2414 - def is_suspended(self, update_status=False):
2415 """\ 2416 Test if the L{X2GoSession}'s terminal session is in suspended state. 2417 2418 @return: C{True} if session is suspended, C{False} otherwise 2419 @rtype: C{bool} 2420 2421 """ 2422 if not update_status: 2423 return self.suspended 2424 2425 if self.is_connected(): 2426 self.suspended = self.control_session.is_suspended(self.get_session_name()) 2427 if self.suspended: 2428 self.running = False 2429 self.terminated = False 2430 self.faulty = False 2431 if self.virgin and not self.suspended: 2432 self.suspended = None 2433 return self.suspended
2434 __is_suspended = is_suspended 2435
2436 - def has_terminated(self, update_status=False):
2437 """\ 2438 Test if the L{X2GoSession}'s terminal session has terminated. 2439 2440 @return: C{True} if session has terminated, C{False} otherwise 2441 @rtype: C{bool} 2442 2443 """ 2444 if not update_status: 2445 return self.terminated 2446 2447 if self.is_connected(): 2448 self.terminated = not self.virgin and self.control_session.has_terminated(self.get_session_name()) 2449 if self.terminated: 2450 self.running = False 2451 self.suspended = False 2452 self.faulty = False 2453 if self.virgin and not self.terminated: 2454 self.terminated = None 2455 return self.terminated
2456 __has_terminated = has_terminated 2457
2459 """\ 2460 Test if the remote session allows sharing of local folders with the session. 2461 2462 @return: returns C{True} if local folder sharing is available in the remote session 2463 @rtype: C{bool} 2464 2465 """ 2466 if self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders: 2467 if self.is_connected(): 2468 return self.control_session.is_sshfs_available() 2469 else: 2470 self.logger('session is not connected, cannot share local folders now', loglevel=log.loglevel_WARN) 2471 else: 2472 self.logger('local folder sharing is disabled for this session profile', loglevel=log.loglevel_WARN) 2473 return False
2474 __is_folder_sharing_available = is_folder_sharing_available 2475
2477 2478 # remember exported folders for restoring them on session suspension/termination 2479 if self.client_instance and self.restore_shared_local_folders: 2480 _exported_folders = copy.deepcopy(self._restore_exported_folders) 2481 for folder in [ sf for sf in self.shared_folders.keys() if self.shared_folders[sf]['status'] in ('new', 'mounted') ]: 2482 _exported_folders.update({ unicode(folder): True }) 2483 for folder in _exported_folders.keys(): 2484 if folder in [ sf for sf in self.shared_folders.keys() if self.shared_folders[sf]['status'] == 'unmounted' ]: 2485 del _exported_folders[unicode(folder)] 2486 self._restore_exported_folders = _exported_folders
2487
2488 - def share_local_folder(self, local_path=None, folder_name=None, update_exported_folders=True):
2489 """\ 2490 Share a local folder with this registered X2Go session. 2491 2492 @param local_path: the full path to an existing folder on the local 2493 file system 2494 @type local_path: C{str} 2495 @param folder_name: synonymous to C{local_path} 2496 @type folder_name: C{str} 2497 @param update_exported_folders: do an update of the session profile option ,,export'' after the operation 2498 @type update_exported_folders: C{bool} 2499 2500 @return: returns C{True} if the local folder has been successfully mounted within 2501 this X2Go session 2502 @rtype: C{bool} 2503 2504 @raise X2GoSessionException: if this L{X2GoSession} does not have an associated terminal session 2505 2506 """ 2507 # compat for Python-X2Go (<=0.1.1.6) 2508 if folder_name: local_path=folder_name 2509 2510 local_path = unicode(local_path) 2511 2512 retval = False 2513 if self.has_terminal_session(): 2514 if self.is_folder_sharing_available() and self.is_master_session(): 2515 2516 # for the sake of non-blocking I/O: let's pretend the action has already been successful 2517 if self.shared_folders.has_key(local_path): 2518 self.shared_folders[local_path]['status'] = 'mounted' 2519 else: 2520 self.shared_folders.update({ local_path: { 'status': 'new', 'mountpoint': '', }, }) 2521 if self.terminal_session.share_local_folder(local_path=local_path): 2522 if update_exported_folders: 2523 self._update_restore_exported_folders() 2524 retval = True 2525 else: 2526 # remove local_path from folder again if the mounting process failed 2527 if self.shared_folders[local_path]['status'] == 'new': 2528 del self.shared_folders[local_path] 2529 else: 2530 self.shared_folders[local_path]['status'] = 'unmounted' 2531 2532 # disable this local folder in session profile if restoring shared folders for following sessions is activated 2533 if self.client_instance and self.restore_shared_local_folders: 2534 if local_path in self._restore_exported_folders.keys(): 2535 self._restore_exported_folders[local_path] = False 2536 2537 else: 2538 raise x2go_exceptions.X2GoSessionException('this X2GoSession object does not have any associated terminal') 2539 return retval
2540 2541 __share_local_folder = share_local_folder 2542
2543 - def share_all_local_folders(self, update_exported_folders=True):
2544 """\ 2545 Share all local folders configured to be mounted within this X2Go session. 2546 2547 @param update_exported_folders: do an update of the session profile option ,,export'' after the operation 2548 @type update_exported_folders: C{bool} 2549 2550 @return: returns C{True} if all local folders could be successfully mounted 2551 inside this X2Go session 2552 @rtype: C{bool} 2553 2554 """ 2555 retval = False 2556 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(): 2557 if self.is_master_session(): 2558 if self.is_folder_sharing_available(): 2559 retval = True 2560 for _folder in self.share_local_folders: 2561 try: 2562 retval = self.share_local_folder(_folder, update_exported_folders=False) and retval 2563 except x2go_exceptions.X2GoUserException, e: 2564 retval = False 2565 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 2566 if update_exported_folders: 2567 self._update_restore_exported_folders() 2568 else: 2569 self.HOOK_foldersharing_not_available() 2570 return retval
2571 __share_all_local_folders = share_all_local_folders 2572
2573 - def unshare_local_folder(self, local_path=None, update_exported_folders=True):
2574 """\ 2575 Unshare a local folder that is mounted within this X2Go session. 2576 2577 @param local_path: the full path to an existing folder on the local 2578 file system that is mounted in this X2Go session and shall be 2579 unmounted 2580 @type local_path: C{str} 2581 @param update_exported_folders: do an update of the session profile option ,,export'' after the operation 2582 @type update_exported_folders: C{bool} 2583 2584 @return: returns C{True} if all local folders could be successfully unmounted 2585 inside this X2Go session 2586 @rtype: C{bool} 2587 2588 @raise X2GoSessionException: if this L{X2GoSession} does not have an associated terminal session 2589 2590 """ 2591 retval = False 2592 2593 local_path = unicode(local_path) 2594 2595 if self.has_terminal_session(): 2596 if self.is_folder_sharing_available() and self.is_master_session() and local_path in self.shared_folders.keys(): 2597 2598 # for the sake of non-blocking I/O: let's pretend the action has already been successful 2599 self.shared_folders[local_path]['status'] = 'unmounted' 2600 if self.terminal_session.unshare_local_folder(local_path=local_path): 2601 retval = True 2602 else: 2603 # if unmounting failed restore the status with ,,mounted'', not sure if that works ok... 2604 self.shared_folders[local_path]['status'] = 'mounted' 2605 2606 else: 2607 raise x2go_exceptions.X2GoSessionException('this X2GoSession object does not have any associated terminal') 2608 2609 return retval
2610 __unshare_local_folder = unshare_local_folder 2611
2612 - def unshare_all_local_folders(self, force_all=False, update_exported_folders=True):
2613 """\ 2614 Unshare all local folders mounted within this X2Go session. 2615 2616 @param force_all: Really unmount _all_ shared folders, including the print spool folder and 2617 the MIME box spool dir (not recommended). 2618 @type force_all: C{bool} 2619 @param update_exported_folders: do an update of the session profile option ,,export'' after the operation 2620 @type update_exported_folders: C{bool} 2621 2622 @return: returns C{True} if all local folders could be successfully unmounted 2623 inside this X2Go session 2624 @rtype: C{bool} 2625 2626 @raise X2GoSessionException: if this L{X2GoSession} does not have an associated terminal session 2627 2628 """ 2629 if self.has_terminal_session(): 2630 if self.is_folder_sharing_available() and self.is_master_session(): 2631 2632 if force_all: 2633 retval = self.terminal_session.unshare_all_local_folders() 2634 if retval: 2635 self.shared_folders = {} 2636 return retval 2637 else: 2638 retval = True 2639 _shared_folders = copy.deepcopy(self.shared_folders) 2640 for _folder in _shared_folders.keys(): 2641 retval = self.unshare_local_folder(_folder, update_exported_folders=False) and retval 2642 if update_exported_folders: 2643 self._update_restore_exported_folders() 2644 return retval 2645 else: 2646 raise x2go_exceptions.X2GoSessionException('this X2GoSession object does not have any associated terminal') 2647 return False
2648 __unshare_all_local_folders = unshare_all_local_folders 2649
2650 - def get_shared_folders(self, check_list_mounts=False, mounts=None):
2651 """\ 2652 Get a list of local folders mounted within this X2Go session from this client. 2653 2654 @param check_list_mounts: if set to C{True} the list of shared folders is referenced against 2655 the latest status of the server-side mount list. 2656 @type check_list_mounts: C{bool} 2657 @param mounts: a server-side dictionary of session name keys and lists of mounted shares (server-side mount points) 2658 @type mounts: C{dict} 2659 2660 @return: returns a C{list} of those local folder names that are mounted with this X2Go session. 2661 @rtype: C{list} 2662 2663 """ 2664 if self.is_folder_sharing_available and self.is_master_session() and self.shared_folders and check_list_mounts: 2665 2666 unshared_folders = [] 2667 if mounts is None: 2668 mounts = self.list_mounts() 2669 _defacto_mounts = [ unicode(m.split('|')[1].split('/')[-1]) for m in mounts ] 2670 2671 for shared_folder in self.shared_folders.keys(): 2672 2673 if _X2GOCLIENT_OS == 'Windows': 2674 _driveletter, _path = os.path.splitdrive(shared_folder) 2675 _mount_point = '_windrive_%s%s' % (_driveletter[0], _path.replace('\\', '_')) 2676 _mount_point = _mount_point.replace(' ', '_') 2677 2678 else: 2679 _mount_point = shared_folder.replace('/', '_') 2680 _mount_point = _mount_point.replace(' ', '_') 2681 2682 self.shared_folders[shared_folder]['status'] = 'mounted' 2683 self.shared_folders[shared_folder]['mountpoint'] = unicode(_mount_point) 2684 2685 for m in _defacto_mounts: 2686 for sf in self.shared_folders.keys(): 2687 if self.shared_folders[sf]['mountpoint'] == m: 2688 self.shared_folders[sf]['status'] = 'mounted' 2689 break 2690 2691 unshared_folders = False 2692 2693 for sf in self.shared_folders.keys(): 2694 m = self.shared_folders[sf]['mountpoint'] 2695 if m and m not in _defacto_mounts: 2696 try: 2697 if self.shared_folders[sf]['status'] == 'mounted': 2698 self.shared_folders[sf]['status'] = 'unmounted' 2699 self.logger('Detected server-side unsharing of client-side folder for profile %s: %s:' % (self.get_profile_name(), sf), loglevel=log.loglevel_INFO) 2700 unshared_folders = True 2701 except IndexError: 2702 pass 2703 2704 if unshared_folders: 2705 self._update_restore_exported_folders() 2706 2707 return [ unicode(sf) for sf in self.shared_folders if self.shared_folders[sf]['status'] in ('new', 'mounted') ]
2708 __get_shared_folders = get_shared_folders 2709
2710 - def is_locked(self):
2711 """\ 2712 Query session if it is locked by some command being processed. 2713 2714 @return: returns C{True} is the session is locked, C{False} if not; returns C{None}, if there is no 2715 control session yet. 2716 @rtype: C{bool} 2717 2718 """ 2719 if self.control_session is not None: 2720 return self.control_session.locked or self.locked 2721 return None
2722 __is_locked = is_locked 2723
2724 - def session_cleanup(self):
2725 """\ 2726 Clean up X2Go session. 2727 2728 """ 2729 # release terminal session's proxy 2730 if self.has_terminal_session(): 2731 self.terminal_session.release_proxy() 2732 2733 # remove client-side session cache 2734 if self.terminated and self.has_terminal_session(): 2735 self.terminal_session.post_terminate_cleanup() 2736 2737 # destroy terminal session 2738 if self.has_terminal_session(): 2739 self.terminal_session.__del__() 2740 2741 self.terminal_session = None
2742 __session_cleanup = session_cleanup
2743