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

Source Code for Module x2go.session

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