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

Source Code for Module x2go.session

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