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

Source Code for Module x2go.session

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