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

Source Code for Module x2go.session

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