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