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

Source Code for Module x2go.session

   1  # -*- coding: utf-8 -*- 
   2   
   3  # Copyright (C) 2010-2011 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 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 General Public License for more details. 
  14  # 
  15  # You should have received a copy of the GNU 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  """ 
  29  __NAME__ = 'x2gosession-pylib' 
  30   
  31  import os 
  32  import copy 
  33  import types 
  34  import uuid 
  35  import time 
  36  import threading 
  37  import gevent 
  38   
  39  # Python X2go modules 
  40  import log 
  41  import utils 
  42  import session 
  43  from x2go_exceptions import * 
  44   
  45  from x2go.backends.control import X2goControlSession as _X2goControlSession 
  46  from x2go.backends.terminal import X2goTerminalSession as _X2goTerminalSession 
  47  from x2go.backends.info import X2goServerSessionInfo as _X2goServerSessionInfo 
  48  from x2go.backends.info import X2goServerSessionList as _X2goServerSessionList 
  49  from x2go.backends.proxy import X2goProxy as _X2goProxy 
  50  from x2go.backends.profiles import X2goSessionProfiles as _X2goSessionProfiles 
  51  from x2go.backends.settings import X2goClientSettings as _X2goClientSettings 
  52  from x2go.backends.printing import X2goClientPrinting as _X2goClientPrinting 
  53   
  54  from defaults import LOCAL_HOME as _LOCAL_HOME 
  55  from defaults import X2GO_CLIENT_ROOTDIR as _X2GO_CLIENT_ROOTDIR 
  56  from defaults import X2GO_SESSIONS_ROOTDIR as _X2GO_SESSIONS_ROOTDIR 
  57  from defaults import X2GO_SSH_ROOTDIR as _X2GO_SSH_ROOTDIR 
  58   
  59  from defaults import SUPPORTED_SOUND, SUPPORTED_PRINTING, SUPPORTED_FOLDERSHARING, SUPPORTED_MIMEBOX 
  60   
  61  # options of the paramiko.SSHClient().connect() 
  62  _X2GO_SESSION_PARAMS = ('geometry', 'depth', 'link', 'pack', 
  63                          'cache_type', 'kblayout', 'kbtype', 
  64                          'session_type', 'snd_system', 'snd_port', 
  65                          'cmd', 
  66                          'rdp_server', 'rdp_options', 
  67                          'xdmcp_server', 
  68                          'rootdir', 'loglevel', 'profile_name', 'profile_id', 
  69                          'print_action', 'print_action_args', 
  70                          'convert_encoding', 'client_encoding', 'server_encoding', 
  71                          'proxy_options',  
  72                          'logger', 
  73                          'control_backend', 'terminal_backend', 'proxy_backend', 
  74                          'profiles_backend', 'settings_backend', 'printing_backend', 
  75                         ) 
  76  """A list of allowed X2go session parameters.""" 
  77  _X2GO_SSHPROXY_PARAMS = ('sshproxy_host', 'sshproxy_user', 'sshproxy_password', 
  78                           'sshproxy_key_filename', 'sshproxy_pkey', 'sshproxy_tunnel', 
  79                          ) 
  80  """A list of allowed X2go SSH proxy parameters.""" 
  81   
  82   
83 -class X2goSession(object):
84 """\ 85 Public API class for launching X2go sessions. Recommended is to manage X2go sessions from 86 within an L{X2goClient} instance. However, Python X2go is designed in a way that it also 87 allows the management of singel L{X2goSession} instance. 88 89 Thus, you can use the L{X2goSession} class to manually set up X2go sessions without 90 L{X2goClient} context (session registry, session list cache, auto-registration of new 91 sessions etc.). 92 93 """
94 - def __init__(self, server=None, control_session=None, 95 use_sshproxy=False, 96 profile_id=None, profile_name='UNKNOWN', 97 session_name=None, 98 printing=False, 99 allow_mimebox=False, 100 mimebox_extensions=[], 101 mimebox_action='OPEN', 102 allow_share_local_folders=False, 103 share_local_folders=[], 104 control_backend=_X2goControlSession, 105 terminal_backend=_X2goTerminalSession, 106 info_backend=_X2goServerSessionInfo, 107 list_backend=_X2goServerSessionList, 108 proxy_backend=_X2goProxy, 109 settings_backend=_X2goClientSettings, 110 printing_backend=_X2goClientPrinting, 111 client_rootdir=os.path.join(_LOCAL_HOME, _X2GO_CLIENT_ROOTDIR), 112 sessions_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SESSIONS_ROOTDIR), 113 ssh_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SSH_ROOTDIR), 114 keep_controlsession_alive=False, 115 add_to_known_hosts=False, 116 known_hosts=None, 117 logger=None, loglevel=log.loglevel_DEFAULT, 118 connected=False, virgin=True, running=None, suspended=None, terminated=None, faulty=None, 119 client_instance=None, 120 **params):
121 """\ 122 @param server: hostname of X2go server 123 @type server: C{str} 124 @param control_session: an already initialized C{X2goControlSession*} instance 125 @type control_session: C{X2goControlSession*} instance 126 @param use_sshproxy: for communication with X2go server use an SSH proxy host 127 @type use_sshproxy: C{bool} 128 @param profile_id: profile ID 129 @type profile_id: C{str} 130 @param profile_name: profile name 131 @type profile_name: C{str} 132 @param session_name: session name (if available) 133 @type session_name: C{str} 134 @param printing: enable X2go printing 135 @type printing: C{bool} 136 @param allow_mimebox: enable X2go MIME box support 137 @type allow_mimebox: C{bool} 138 @param mimebox_extensions: whitelist of allowed X2go MIME box extensions 139 @type mimebox_extensions: C{list} 140 @param mimebox_action: action for incoming X2go MIME box files 141 @type mimebox_action: C{X2goMimeBoxAction*} or C{str} 142 @param allow_share_local_folders: enable local folder sharing support 143 @type allow_share_local_folders: C{bool} 144 @param share_local_folders: list of local folders to share with the remote X2go session 145 @type share_local_folders: C{list} 146 @param control_backend: X2go control session backend to use 147 @type control_backend: C{class} 148 @param terminal_backend: X2go terminal session backend to use 149 @type terminal_backend: C{class} 150 @param info_backend: X2go session info backend to use 151 @type info_backend: C{class} 152 @param list_backend: X2go session list backend to use 153 @type list_backend: C{class} 154 @param proxy_backend: X2go proxy backend to use 155 @type proxy_backend: C{class} 156 @param settings_backend: X2go client settings backend to use 157 @type settings_backend: C{class} 158 @param printing_backend: X2go client printing backend to use 159 @type printing_backend: C{class} 160 @param client_rootdir: client base dir (default: ~/.x2goclient) 161 @type client_rootdir: C{str} 162 @param sessions_rootdir: sessions base dir (default: ~/.x2go) 163 @type sessions_rootdir: C{str} 164 @param ssh_rootdir: ssh base dir (default: ~/.ssh) 165 @type ssh_rootdir: C{str} 166 @param keep_controlsession_alive: On last L{X2goSession.disconnect()} keep the associated C{X2goControlSession*} instance alive? 167 @ŧype keep_controlsession_alive: C{bool} 168 @param add_to_known_hosts: Auto-accept server host validity? 169 @type add_to_known_hosts: C{bool} 170 @param known_hosts: the underlying Paramiko/SSH systems C{known_hosts} file 171 @type known_hosts: C{str} 172 @param connected: manipulate session state »connected« by giving a pre-set value 173 @type connected: C{bool} 174 @param virgin: manipulate session state »virgin« by giving a pre-set value 175 @type virgin: C{bool} 176 @param running: manipulate session state »running« by giving a pre-set value 177 @type running: C{bool} 178 @param suspended: manipulate session state »suspended« by giving a pre-set value 179 @type suspended: C{bool} 180 @param terminated: manipulate session state »terminated« by giving a pre-set value 181 @type terminated: C{bool} 182 @param faulty: manipulate session state »faulty« by giving a pre-set value 183 @type faulty: C{bool} 184 @param client_instance: if available, the underlying L{X2goClient} instance 185 @type client_instance: C{X2goClient} instance 186 @param params: further control session, terminal session and SSH proxy class options 187 @type params: C{dict} 188 189 """ 190 if logger is None: 191 self.logger = log.X2goLogger(loglevel=loglevel) 192 else: 193 self.logger = copy.deepcopy(logger) 194 self.logger.tag = __NAME__ 195 196 self._keep = None 197 198 self.uuid = uuid.uuid1() 199 self.connected = connected 200 201 self.virgin = virgin 202 self.running = running 203 self.suspended = suspended 204 self.terminated = terminated 205 self.faulty = faulty 206 self.keep_controlsession_alive = keep_controlsession_alive 207 208 self.profile_id = profile_id 209 self.profile_name = profile_name 210 self.session_name = session_name 211 self.server = server 212 213 self._last_status = None 214 215 self.locked = False 216 217 self.printing = printing 218 self.allow_share_local_folders = allow_share_local_folders 219 self.share_local_folders = share_local_folders 220 self.allow_mimebox = allow_mimebox 221 self.mimebox_extensions = mimebox_extensions 222 self.mimebox_action = mimebox_action 223 self.control_backend = control_backend 224 self.terminal_backend = terminal_backend 225 self.info_backend = info_backend 226 self.list_backend = list_backend 227 self.proxy_backend = proxy_backend 228 self.settings_backend = settings_backend 229 self.printing_backend = printing_backend 230 self.client_rootdir = client_rootdir 231 self.sessions_rootdir = sessions_rootdir 232 self.ssh_rootdir = ssh_rootdir 233 self.control_session = control_session 234 235 self.control_params = {} 236 self.terminal_params = {} 237 self.sshproxy_params = {} 238 self.update_params(params) 239 self.shared_folders = [] 240 241 self.session_environment = {} 242 243 try: del self.control_params['server'] 244 except: pass 245 246 self.client_instance = client_instance 247 248 if self.logger.get_loglevel() & log.loglevel_DEBUG: 249 self.logger('X2go control session parameters for profile %s:' % profile_name, loglevel=log.loglevel_DEBUG) 250 for p in self.control_params: 251 self.logger(' %s: %s' % (p, self.control_params[p]), log.loglevel_DEBUG) 252 self.logger('X2go terminal session parameters for profile %s:' % profile_name, loglevel=log.loglevel_DEBUG) 253 for p in self.terminal_params: 254 self.logger(' %s: %s' % (p,self.terminal_params[p]), log.loglevel_DEBUG) 255 self.logger('X2go sshproxy parameters for profile %s:' % profile_name, loglevel=log.loglevel_DEBUG) 256 for p in self.sshproxy_params: 257 self.logger(' %s: %s' % (p,self.sshproxy_params[p]), loglevel=log.loglevel_DEBUG) 258 259 self.add_to_known_hosts = add_to_known_hosts 260 self.known_hosts = known_hosts 261 self.use_sshproxy = use_sshproxy 262 263 self._current_status = { 264 'timestamp': time.time(), 265 'server': self.server, 266 'virgin': self.virgin, 267 'connected': self.connected, 268 'running': self.running, 269 'suspended': self.suspended, 270 'terminated': self.terminated, 271 'faulty': self.faulty, 272 } 273 274 self._SUPPORTED_SOUND = SUPPORTED_SOUND 275 self._SUPPORTED_PRINTING = SUPPORTED_PRINTING 276 self._SUPPORTED_MIMEBOX = SUPPORTED_MIMEBOX 277 self._SUPPORTED_FOLDERSHARING = SUPPORTED_FOLDERSHARING 278 279 self.init_control_session() 280 self.terminal_session = None
281
283 """\ 284 HOOK method: called if the startup of a session failed. 285 286 """ 287 if self.client_instance: 288 self.client_instance.HOOK_session_startup_failed(profile_name=self.profile_name) 289 else: 290 self.logger('HOOK_session_startup_failed: session startup for session profile ,,%s'' failed.' % self.profile_name, loglevel=log.loglevel_WARN)
291
292 - def HOOK_rforward_request_denied(self, server_port=0):
293 """\ 294 HOOK method: called if a reverse port forwarding request has been denied. 295 296 @param server_port: remote server port (starting point of reverse forwarding tunnel) 297 @type server_port: C{str} 298 299 """ 300 if self.client_instance: 301 self.client_instance.HOOK_rforward_request_denied(profile_name=self.profile_name, session_name=self.session_name, server_port=server_port) 302 else: 303 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)
304
305 - def HOOK_forwarding_tunnel_setup_failed(self, chain_host='UNKNOWN', chain_port=0):
306 """\ 307 HOOK method: called if a port forwarding tunnel setup failed. 308 309 @param chain_host: hostname of chain host (forwarding tunnel end point) 310 @type chain_host: C{str} 311 @param chain_port: port of chain host (forwarding tunnel end point) 312 @type chain_port: C{str} 313 314 """ 315 # mark session as faulty 316 self.faulty = True 317 318 if self.client_instance: 319 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) 320 else: 321 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) 322 323 # get rid of the faulty session... 324 self.terminate()
325
326 - def HOOK_check_host_dialog(self, host, port, fingerprint='no fingerprint', fingerprint_type='RSA'):
327 """\ 328 HOOK method: called if a host check is requested. This hook has to either return C{True} (default) or C{False}. 329 330 @param host: SSH server name to validate 331 @type host: C{str} 332 @param port: SSH server port to validate 333 @type port: C{int} 334 @param fingerprint: the server's fingerprint 335 @type fingerprint: C{str} 336 @param fingerprint_type: finger print type (like RSA, DSA, ...) 337 @type fingerprint_type: C{str} 338 @return: if host validity is verified, this hook method should return C{True} 339 @rtype: C{bool} 340 341 """ 342 if self.client_instance: 343 return self.client_instance.HOOK_check_host_dialog(profile_name=self.profile_name, host=host, port=port, fingerprint=fingerprint, fingerprint_type=fingerprint_type) 344 else: 345 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) 346 return True
347
348 - def init_control_session(self):
349 """\ 350 Initialize a new control session (C{X2goControlSession*}). 351 352 """ 353 if self.control_session is None: 354 self.logger('initializing X2goControlSession', loglevel=log.loglevel_DEBUG) 355 self.control_session = self.control_backend(profile_name=self.profile_name, 356 add_to_known_hosts=self.add_to_known_hosts, 357 known_hosts=self.known_hosts, 358 terminal_backend=self.terminal_backend, 359 info_backend=self.info_backend, 360 list_backend=self.list_backend, 361 proxy_backend=self.proxy_backend, 362 client_rootdir=self.client_rootdir, 363 sessions_rootdir=self.sessions_rootdir, 364 ssh_rootdir=self.ssh_rootdir, 365 logger=self.logger)
366
367 - def set_server(self, server):
368 """\ 369 Modify server name after L{X2goSession} has already been initialized. 370 371 @param server: new server name 372 @type server: C{str} 373 374 """ 375 self.server = server
376
377 - def set_profile_name(self, profile_name):
378 """\ 379 Modify session profile name after L{X2goSession} has already been initialized. 380 381 @param profile_name: new session profile name 382 @type profile_name: C{str} 383 384 """ 385 self.profile_name = profile_name 386 self.control_session.set_profile_name(profile_name)
387
388 - def __str__(self):
389 return self.__get_uuid()
390
391 - def __repr__(self):
392 result = 'X2goSession(' 393 for p in dir(self): 394 if '__' in p or not p in self.__dict__ or type(p) is types.InstanceType: continue 395 result += p + '=' + str(self.__dict__[p]) + ', ' 396 return result + ')'
397
398 - def __call__(self):
399 return self.__get_uuid()
400
401 - def __del__(self):
402 """\ 403 Class destructor. 404 405 """ 406 if self.has_control_session() and self.has_terminal_session(): 407 self.get_control_session().dissociate(self.get_terminal_session()) 408 409 if self.has_control_session(): 410 if self.keep_controlsession_alive: 411 # regenerate this session instance for re-usage if this is the last session for a certain session profile 412 # and keep_controlsession_alive is set to True... 413 self.virgin = True 414 self.connected = self.is_connected() 415 self.running = None 416 self.suspended = None 417 self.terminated = None 418 self._current_status = { 419 'timestamp': time.time(), 420 'server': self.server, 421 'virgin': self.virgin, 422 'connected': self.connected, 423 'running': self.running, 424 'suspended': self.suspended, 425 'terminated': self.terminated, 426 'faulty': self.faulty, 427 } 428 self._last_status = None 429 self.session_name = None 430 431 else: 432 self.get_control_session().__del__() 433 self.control_session = None 434 435 if self.has_terminal_session(): 436 self.get_terminal_session().__del__() 437 self.terminal_session = None
438
439 - def update_params(self, params):
440 """\ 441 This method can be used to modify L{X2goSession} parameters after the 442 L{X2goSession} instance has already been initialized. 443 444 @param params: a Python dictionary with L{X2goSession} parameters 445 @type params: C{dict} 446 447 """ 448 try: del params['server'] 449 except KeyError: pass 450 try: del params['profile_name'] 451 except KeyError: pass 452 try: del params['profile_id'] 453 except KeyError: pass 454 try: 455 self.printing = params['printing'] 456 del params['printing'] 457 except KeyError: pass 458 try: 459 self.allow_share_local_folders = params['allow_share_local_folders'] 460 del params['allow_share_local_folders'] 461 except KeyError: pass 462 try: 463 self.share_local_folders = params['share_local_folders'] 464 del params['share_local_folders'] 465 except KeyError: pass 466 try: 467 self.allow_mimebox = params['allow_mimebox'] 468 del params['allow_mimebox'] 469 except KeyError: pass 470 try: 471 self.mimebox_extensions = params['mimebox_extensions'] 472 del params['mimebox_extensions'] 473 except KeyError: pass 474 try: 475 self.mimebox_action = params['mimebox_action'] 476 del params['mimebox_action'] 477 except KeyError: pass 478 try: 479 self.use_sshproxy = params['use_sshproxy'] 480 del params['use_sshproxy'] 481 except KeyError: pass 482 483 _terminal_params = copy.deepcopy(params) 484 _control_params = copy.deepcopy(params) 485 _sshproxy_params = copy.deepcopy(params) 486 for p in params.keys(): 487 if p in session._X2GO_SESSION_PARAMS: 488 del _control_params[p] 489 del _sshproxy_params[p] 490 elif p in session._X2GO_SSHPROXY_PARAMS: 491 del _control_params[p] 492 del _terminal_params[p] 493 else: 494 del _sshproxy_params[p] 495 del _terminal_params[p] 496 497 self.control_params.update(_control_params) 498 self.terminal_params.update(_terminal_params) 499 self.sshproxy_params.update(_sshproxy_params)
500
501 - def get_uuid(self):
502 """\ 503 Retrieve session UUID hash for this L{X2goSession}. 504 505 """ 506 return str(self.uuid)
507 __get_uuid = get_uuid 508
509 - def get_username(self):
510 """\ 511 After a session has been set up you can query the 512 username the sessions runs as. 513 514 @return: the remote username the X2go session runs as 515 @rtype: C{str} 516 517 """ 518 # try to retrieve the username from the control session, if already connected 519 try: 520 return self.control_session.get_transport().get_username() 521 except AttributeError: 522 return self.control_params['username']
523 __get_username = get_username 524 525
526 - def user_is_x2gouser(self, username=None):
527 """\ 528 Check if a given user is valid server-side X2go user. 529 530 @param username: username to check validity for 531 @type username: C{str} 532 @return: return C{True} if the username is allowed to launch X2go sessions 533 @rtype: C{bool} 534 535 """ 536 if username is None: 537 username = self.__get_username() 538 return self.control_session.is_x2gouser(username)
539 __user_is_x2gouser = user_is_x2gouser 540
541 - def get_password(self):
542 """\ 543 After a session has been setup up you can query the 544 username's password from the session. 545 546 @return: the username's password 547 @rtype: C{str} 548 549 """ 550 return self.control_session._session_password
551 __get_password = get_password 552
553 - def get_server_peername(self):
554 """\ 555 After a session has been setup up you can query the 556 peername of the host this session is connected to (or 557 about to connect to). 558 559 @return: the address of the server the X2go session is 560 connected to (as an C{(addr,port)} tuple) 561 @rtype: C{tuple} 562 563 """ 564 return self.control_session.get_transport().getpeername()
565 __get_server_peername = get_server_peername 566
567 - def get_server_hostname(self):
568 """\ 569 After a session has been setup up you can query the 570 hostname of the host this session is connected to (or 571 about to connect to). 572 573 @return: the hostname of the server the X2go session is 574 connected to / about to connect to 575 @rtype: C{str} 576 577 """ 578 self.server = self.control_session.hostname 579 return self.server
580 __get_server_hostname = get_server_hostname 581
582 - def get_server_port(self):
583 """\ 584 After a session has been setup up you can query the 585 IP socket port used for connecting the remote X2go server. 586 587 @return: the server-side IP socket port that is used by the X2go session to 588 connect to the server 589 @rtype: C{str} 590 591 """ 592 return self.control_session.port
593 __get_server_port = get_server_port 594
595 - def get_session_name(self):
596 """\ 597 Retrieve the server-side X2go session name for this session. 598 599 @return: X2go session name 600 @rtype: C{str} 601 602 """ 603 return self.session_name
604 __get_session_name = get_session_name 605
606 - def get_session_cmd(self):
607 """\ 608 Retrieve the server-side command that is used to start a session 609 on the remote X2go server. 610 611 @return: server-side session command 612 @rtype: C{str} 613 614 """ 615 if self.terminal_params.has_key('cmd'): 616 return self.terminal_params['cmd'] 617 return None
618 __get_session_cmd = get_session_cmd 619
620 - def get_control_session(self):
621 """\ 622 Retrieve the control session (C{X2goControlSession*} backend) of this L{X2goSession}. 623 624 @return: the L{X2goSession}'s control session 625 @rtype: C{X2goControlSession*} instance 626 """ 627 return self.control_session
628 __get_control_session = get_control_session 629
630 - def has_control_session(self):
631 """\ 632 Check if this L{X2goSession} instance has an associated control session. 633 634 @return: returns C{True} if this L{X2goSession} has a control session associated to itself 635 @rtype: C{bool} 636 637 """ 638 return self.control_session is not None
639 __has_control_session = has_control_session 640
641 - def get_terminal_session(self):
642 """\ 643 Retrieve the terminal session (C{X2goTerminalSession*} backend) of this L{X2goSession}. 644 645 @return: the L{X2goSession}'s terminal session 646 @rtype: C{X2goControlTerminal*} instance 647 648 """ 649 if self.terminal_session == 'PENDING': 650 return None 651 return self.terminal_session
652 __get_terminal_session = get_terminal_session 653
654 - def has_terminal_session(self):
655 """\ 656 Check if this L{X2goSession} instance has an associated terminal session. 657 658 @return: returns C{True} if this L{X2goSession} has a terminal session associated to itself 659 @rtype: C{bool} 660 661 662 """ 663 return self.terminal_session not in (None, 'PENDING')
664 __has_terminal_session = has_terminal_session 665
666 - def check_host(self):
667 """\ 668 Provide a host check mechanism. This method basically calls the L{HOOK_check_host_dialog()} method 669 which by itself calls the L{X2goClient.HOOK_check_host_dialog()} method. Make sure you 670 override any of these to enable user interaction on X2go server validity checks. 671 672 @return: returns C{True} if an X2go server host is valid for authentication 673 @rtype: C{bool} 674 675 """ 676 if self.connected: 677 return True 678 679 _port = self.control_params['port'] 680 (_valid, _host, _port, _fingerprint, _fingerprint_type) = self.control_session.check_host(self.server, port=_port) 681 return _valid or self.HOOK_check_host_dialog(host=_host, port=_port, fingerprint=_fingerprint, fingerprint_type=_fingerprint_type)
682 __check_host = check_host 683
684 - def uses_sshproxy(self):
685 """\ 686 Check if a session is configured to use an intermediate SSH proxy server. 687 688 @return: returns C{True} if the session is configured to use an SSH proxy, C{False} otherwise. 689 @rtype: C{bool} 690 691 """ 692 return self.use_sshproxy
693
694 - def can_sshproxy_auto_connect(self):
695 """\ 696 Check if a session's SSH proxy (if used) is configured adequately to be able to auto-connect 697 to the SSH proxy server (e.g. by public key authentication). 698 699 @return: returns C{True} if the session's SSH proxy can auto-connect, C{False} otherwise, C{None} 700 if no SSH proxy is used for this session, C{None} is returned. 701 @rtype: C{bool} 702 703 """ 704 if self.use_sshproxy: 705 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'])): 706 return True 707 elif self.sshproxy_params.has_key('sshproxy_pkey') and self.sshproxy_params['sshproxy_pkey']: 708 return True 709 else: 710 return False 711 else: 712 return None
713 __can_sshproxy_auto_connect = can_sshproxy_auto_connect 714
715 - def can_auto_connect(self):
716 """\ 717 Check if a session is configured adequately to be able to auto-connect to the X2go 718 server (e.g. public key authentication). 719 720 @return: returns C{True} if the session can auto-connect, C{False} otherwise, C{None} 721 if no control session has been set up yet. 722 @rtype: C{bool} 723 724 """ 725 if self.control_session is None: 726 return None 727 728 # do we have a key file passed as control parameter? 729 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'])): 730 _can_sshproxy_auto_connect = self.can_sshproxy_auto_connect() 731 if _can_sshproxy_auto_connect is not None: 732 return _can_sshproxy_auto_connect 733 else: 734 return True 735 736 # or a private key? 737 elif self.control_params.has_key('pkey') and self.control_params['pkey']: 738 _can_sshproxy_auto_connect = self.can_sshproxy_auto_connect() 739 if _can_sshproxy_auto_connect is not None: 740 return _can_sshproxy_auto_connect 741 else: 742 return True 743 744 else: 745 return False
746 __can_auto_connect = can_auto_connect 747
748 - def connect(self, username='', password='', add_to_known_hosts=False, force_password_auth=False, 749 use_sshproxy=False, sshproxy_user='', sshproxy_password=''):
750 """\ 751 Connects to the L{X2goSession}'s server host. This method basically wraps around 752 the C{X2goControlSession*.connect()} method. 753 754 @param username: the username for the X2go server that is going to be 755 connected to (as a last minute way of changing the session username) 756 @type username: C{str} 757 @param password: the user's password for the X2go server that is going to be 758 connected to 759 @type password: C{str} 760 @param add_to_known_hosts: non-paramiko option, if C{True} paramiko.AutoAddPolicy() 761 is used as missing-host-key-policy. If set to C{False} paramiko.RejectPolicy() 762 is used 763 @type add_to_known_hosts: C{bool} 764 @param force_password_auth: disable SSH pub/priv key authentication mechanisms 765 completely 766 @type force_password_auth: C{bool} 767 @param use_sshproxy: use an SSH proxy host for connecting the target X2go server 768 @type use_sshproxy: C{bool} 769 @param sshproxy_user: username for authentication against the SSH proxy host 770 @type sshproxy_user: C{str} 771 @param sshproxy_password: password for authentication against the SSH proxy host 772 @type sshproxy_password: C{str} 773 774 @return: returns C{True} is the connection to the X2go server has been successful 775 @rtype C{bool} 776 777 """ 778 if self.control_session and self.control_session.is_connected(): 779 self.logger('control session is already connected, skipping authentication', loglevel=log.loglevel_DEBUG) 780 self.connected = True 781 else: 782 if username: 783 self.control_params['username'] = username 784 if add_to_known_hosts is not None: 785 self.control_params['add_to_known_hosts'] = add_to_known_hosts 786 if force_password_auth is not None: 787 self.control_params['force_password_auth'] = force_password_auth 788 if sshproxy_user: 789 self.sshproxy_params['sshproxy_user'] = sshproxy_user 790 if sshproxy_password: 791 self.sshproxy_params['sshproxy_password'] = sshproxy_password 792 self.control_params['password'] = password 793 794 _params = {} 795 _params.update(self.control_params) 796 _params.update(self.sshproxy_params) 797 798 try: 799 self.connected = self.control_session.connect(self.server, 800 use_sshproxy=self.use_sshproxy, 801 session_instance=self, 802 **_params) 803 except X2goControlSessionException, e: 804 raise X2goSessionException(str(e)) 805 except X2goRemoteHomeException, e: 806 self.disconnect() 807 raise e 808 except: 809 # remove credentials immediately 810 self.control_params['password'] = '' 811 if self.sshproxy_params and self.sshproxy_params.has_key('sshproxy_password'): 812 del self.sshproxy_params['sshproxy_password'] 813 raise 814 finally: 815 # remove credentials immediately 816 self.control_params['password'] = '' 817 if self.sshproxy_params and self.sshproxy_params.has_key('sshproxy_password'): 818 del self.sshproxy_params['sshproxy_password'] 819 820 if not self.connected: 821 # then tidy up... 822 self.disconnect() 823 824 _dummy = self.get_server_hostname() 825 826 if self.connected: 827 self.update_status() 828 829 return self.connected
830 __connect = connect 831
832 - def disconnect(self):
833 """\ 834 Disconnect this L{X2goSession} instance. 835 836 @return: returns C{True} if the disconnect operation has been successful 837 @rtype: C{bool} 838 839 """ 840 self.connected = False 841 self.running = None 842 self.suspended = None 843 self.terminated = None 844 self.faults = None 845 try: 846 self.update_status(force_update=True) 847 except X2goControlSessionException: 848 pass 849 retval = self.control_session.disconnect() 850 return retval
851 __disconnect = disconnect 852
853 - def set_print_action(self, print_action, **kwargs):
854 """\ 855 If X2go client-side printing is enable within this X2go session you can use 856 this method to alter the way how incoming print spool jobs are handled/processed. 857 858 For further information, please refer to the documentation of the L{X2goClient.set_session_print_action()} 859 method. 860 861 @param print_action: one of the named above print actions, either as string or class instance 862 @type print_action: C{str} or C{instance} 863 @param kwargs: additional information for the given print action (print 864 action arguments), for possible print action arguments and their values see each individual 865 print action class 866 @type kwargs: C{dict} 867 868 """ 869 if type(print_action) is not types.StringType: 870 return False 871 self.terminal_session.set_print_action(print_action, **kwargs)
872 __set_print_action = set_print_action 873
874 - def is_alive(self):
875 """\ 876 Find out if this X2go session is still alive (that is: connected to the server). 877 878 @return: returns C{True} if the server connection is still alive 879 @rtype: C{bool} 880 881 """ 882 self.connected = self.control_session.is_alive() 883 if not self.connected: 884 self._X2goSession__disconnect() 885 return self.connected
886 __is_alive = is_alive 887
888 - def clean_sessions(self, destroy_terminals=True):
889 """\ 890 Clean all running sessions for the authenticated user on the remote X2go server. 891 892 """ 893 if self.is_alive(): 894 self.control_session.clean_sessions(destroy_terminals=destroy_terminals) 895 else: 896 self._X2goSession__disconnect()
897 __clean_sessions = clean_sessions 898
899 - def list_sessions(self, raw=False):
900 """\ 901 List all sessions on the remote X2go server that are owned by the authenticated user 902 903 @param raw: if C{True} the output of this method equals 904 the output of the server-side C{x2golistsessions} command 905 @type raw: C{bool} 906 907 @return: a session list (as data object or list of strings when called with C{raw=True} option) 908 @rtype: C{X2goServerSessionList*} instance or C{list} 909 910 """ 911 try: 912 return self.control_session.list_sessions(raw=raw) 913 except X2goControlSessionException: 914 self._X2goSession__disconnect() 915 return None
916 __list_sessions = list_sessions 917
918 - def list_desktops(self, raw=False):
919 """\ 920 List X2go desktops sessions available for desktop sharing on the remote X2go server. 921 922 @param raw: if C{True} the output of this method equals 923 the output of the server-side C{x2golistdesktops} command 924 @type raw: C{bool} 925 926 @return: a list of strings representing available desktop sessions 927 @rtype: C{list} 928 929 """ 930 try: 931 return self.control_session.list_desktops(raw=raw) 932 except X2goDesktopSharingException: 933 if raw: 934 return ('','') 935 else: 936 return [] 937 except X2goControlSessionException: 938 self._X2goSession__disconnect() 939 return None
940 __list_desktops = list_desktops 941
942 - def update_status(self, session_list=None, force_update=False):
943 """\ 944 Update the current session status. The L{X2goSession} instance uses an internal 945 session status cache that allows to query the session status without the need 946 of retrieving data from the remote X2go server for each query. 947 948 The session status (if initialized properly with the L{X2goClient} constructor gets 949 updated in regularly intervals. 950 951 In case you use the L{X2goSession} class in standalone instances (that is: without 952 being embedded into an L{X2goSession} context) then run this method in regular 953 intervals to make sure the L{X2goSession}'s internal status cache information 954 is always up-to-date. 955 956 @param session_list: provide an C{X2goServerSessionList*} that refers to X2go sessions we want to update. 957 This option is mainly for reducing server/client traffic. 958 @type session_list: C{X2goServerSessionList*} instance 959 @param force_update: force a session status update, if if the last update is less then 1 second ago 960 @type force_update: C{bool} 961 962 """ 963 if not force_update and self._last_status is not None: 964 _status_update_timedelta = time.time() - self._last_status['timestamp'] 965 966 # skip this session status update if not longer than a second ago... 967 if _status_update_timedelta < 1: 968 self.logger('status update interval too short (%s), skipping status update this time...' % _status_update_timedelta, loglevel=log.loglevel_DEBUG) 969 return False 970 971 e = None 972 self._last_status = copy.deepcopy(self._current_status) 973 if session_list is None: 974 try: 975 session_list = self.control_session.list_sessions() 976 self.connected = True 977 except X2goControlSessionException, e: 978 self.connected = False 979 self.running = None 980 self.suspended = None 981 self.terminated = None 982 self.faulty = None 983 984 if self.connected: 985 try: 986 _session_name = self.get_session_name() 987 _session_info = session_list[_session_name] 988 self.running = _session_info.is_running() 989 self.suspended = _session_info.is_suspended() 990 if not self.virgin: 991 self.terminated = not (self.running or self.suspended) 992 else: 993 self.terminated = None 994 except KeyError: 995 self.running = False 996 self.suspended = False 997 if not self.virgin: 998 self.terminated = True 999 self.faulty = not (self.running or self.suspended or self.terminated or self.virgin) 1000 1001 1002 self._current_status = { 1003 'timestamp': time.time(), 1004 'server': self.server, 1005 'virgin': self.virgin, 1006 'connected': self.connected, 1007 'running': self.running, 1008 'suspended': self.suspended, 1009 'terminated': self.terminated, 1010 'faulty': self.faulty, 1011 } 1012 1013 if (not self.connected or self.faulty) and e: 1014 raise e 1015 1016 return True
1017 1018 __update_status = update_status 1019
1020 - def resume(self, session_name=None):
1021 """\ 1022 Resume or continue a suspended / running X2go session on the 1023 remote X2go server. 1024 1025 @param session_name: the server-side name of an X2go session 1026 @type session_name: C{str} 1027 1028 @return: returns C{True} if resuming the session has been successful, C{False} otherwise 1029 @rtype: C{bool} 1030 1031 """ 1032 self.terminal_session = 'PENDING' 1033 _new_session = False 1034 if self.session_name is None: 1035 self.session_name = session_name 1036 1037 if self.is_alive(): 1038 _control = self.control_session 1039 1040 # FIXME: normally this part gets called if you suspend a session that is associated to another client 1041 # we do not have a possibility to really check if SSH has released port forwarding channels or 1042 # sockets, thus we plainly have to wait a while 1043 if self.is_running(): 1044 self.suspend() 1045 gevent.sleep(10) 1046 1047 self.terminal_session = _control.resume(session_name=self.session_name, 1048 session_instance=self, 1049 logger=self.logger, **self.terminal_params) 1050 1051 if self.session_name is None: 1052 _new_session = True 1053 try: 1054 self.session_name = self.terminal_session.session_info.name 1055 except AttributeError: 1056 self.HOOK_session_startup_failed() 1057 return False 1058 1059 if self.has_terminal_session() and not self.faulty: 1060 1061 # only run the session startup command if we do not resume... 1062 if _new_session: 1063 self.terminal_session.run_command(env=self.session_environment) 1064 1065 if self._SUPPORTED_SOUND and self.terminal_session.params.snd_system is not 'none': 1066 self.terminal_session and not self.faulty and self.terminal_session.start_sound() 1067 else: 1068 self._SUPPORTED_SOUND = False 1069 1070 try: 1071 if (self._SUPPORTED_PRINTING and self.printing) or \ 1072 (self._SUPPORTED_MIMEBOX and self.allow_mimebox) or \ 1073 (self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders): 1074 self.terminal_session and not self.faulty and self.terminal_session.start_sshfs() 1075 except X2goUserException, e: 1076 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 1077 # TODO: handle this exception as a notification hook method... 1078 self._SUPPORTED_PRINTING = False 1079 self._SUPPORTED_MIMEBOX = False 1080 self._SUPPORTED_FOLDERSHARING = False 1081 1082 try: 1083 if SUPPORTED_PRINTING and self.printing: 1084 self.terminal_session and not self.faulty and self.terminal_session.start_printing() 1085 self.terminal_session and not self.faulty and self.session_environment.update({'X2GO_SPOOLDIR': self.terminal_session.get_printing_spooldir(), }) 1086 except X2goUserException, e: 1087 self.logger('%s' % str(e), loglevel=log.loglevel_WARN) 1088 # TODO: handle this exception as a notification hook method... 1089 self._SUPPORTED_PRINTING = False 1090 1091 if self._SUPPORTED_MIMEBOX and self.allow_mimebox: 1092 self.terminal_session and not self.faulty and self.terminal_session.start_mimebox(mimebox_extensions=self.mimebox_extensions, mimebox_action=self.mimebox_action) 1093 self.terminal_session and self.session_environment.update({'X2GO_MIMEBOX': self.terminal_session.get_mimebox_spooldir(), }) 1094 1095 if self.share_local_folders and self.terminal_session and not self.faulty and self.is_folder_sharing_available(): 1096 if _control.get_transport().reverse_tunnels[self.terminal_session.get_session_name()]['sshfs'][1] is not None: 1097 for _folder in self.share_local_folders: 1098 self.share_local_folder(_folder) 1099 1100 self.virgin = False 1101 self.suspended = False 1102 self.running = True 1103 self.terminated = False 1104 self.faulty = False 1105 1106 return True 1107 1108 else: 1109 self.terminal_session = None 1110 return False 1111 1112 return self.running 1113 else: 1114 self._X2goSession__disconnect() 1115 return False
1116 1117 __resume = resume 1118
1119 - def start(self):
1120 """\ 1121 Start a new X2go session on the remote X2go server. 1122 1123 @return: returns C{True} if starting the session has been successful, C{False} otherwise 1124 @rtype: C{bool} 1125 1126 """ 1127 self.session_name = None 1128 return self.resume()
1129 __start = start 1130
1131 - def share_desktop(self, desktop=None, user=None, display=None, share_mode=0, check_desktop_list=True):
1132 """\ 1133 Share an already running X2go session on the remote X2go server locally. The shared session may be either 1134 owned by the same user or by a user that grants access to his/her desktop session by the local user. 1135 1136 @param desktop: desktop ID of a sharable desktop in format <user>@<display> 1137 @type desktop: C{str} 1138 @param user: user name and display number can be given separately, here give the 1139 name of the user who wants to share a session with you. 1140 @type user: C{str} 1141 @param display: user name and display number can be given separately, here give the 1142 number of the display that a user allows you to be shared with. 1143 @type display: C{str} 1144 @param share_mode: desktop sharing mode, 0 is VIEW-ONLY, 1 is FULL-ACCESS. 1145 @type share_mode: C{int} 1146 @param check_desktop_list: check if the given desktop is available on the X2go server; handle with care as 1147 the server-side C{x2golistdesktops} command might block client I/O. 1148 @type check_desktop_list: C{bool} 1149 1150 @return: returns C{True} if starting the session has been successful, C{False} otherwise 1151 @rtype: C{bool} 1152 1153 """ 1154 self.terminal_session = 'PENDING' 1155 1156 _desktop = desktop or '%s@%s' % (user, display) 1157 if check_desktop_list: 1158 if not _desktop in self._X2goSession__list_desktops(): 1159 _orig_desktop = _desktop 1160 _desktop = '%s.0' % _desktop 1161 if not _desktop in self._X2GoSession__list_desktops(): 1162 raise X2goDesktopSharingException('No such desktop ID: %s' % _orig_desktop) 1163 1164 _session_owner = _desktop.split('@')[0] 1165 _display = _desktop.split('@')[1] 1166 1167 if self.is_alive(): 1168 if self.get_username() != _session_owner: 1169 self.logger('waiting for user ,,%s\'\' to interactively grant you access to his/her desktop session...' % _session_owner, loglevel=log.loglevel_NOTICE) 1170 self.logger('THIS MAY TAKE A WHILE!', loglevel=log.loglevel_NOTICE) 1171 1172 _control = self.control_session 1173 try: 1174 self.terminal_session = _control.share_desktop(desktop=_desktop, share_mode=share_mode, 1175 logger=self.logger, **self.terminal_params) 1176 except ValueError: 1177 # x2gostartagent output parsing will result in a ValueError. This one we will catch 1178 # here and change it into an X2goSessionException 1179 raise X2goSessionException('the session on desktop %s is seemingly dead' % _desktop) 1180 1181 if self.has_terminal_session(): 1182 self.session_name = self.terminal_session.session_info.name 1183 1184 # shared desktop sessions get their startup command set by the control 1185 # session, run this pre-set command now... 1186 self.terminal_session.run_command(env=self.session_environment) 1187 1188 self.virgin = False 1189 self.suspended = False 1190 self.running = True 1191 self.terminated = False 1192 self.faulty = False 1193 1194 return self.running 1195 else: 1196 self.terminal_session = None 1197 1198 else: 1199 self._X2goSession__disconnect() 1200 1201 return False
1202 __share_desktop = share_desktop 1203
1204 - def suspend(self):
1205 """\ 1206 Suspend this X2go session. 1207 1208 @return: returns C{True} if suspending the session has been successful, C{False} otherwise 1209 @rtype: C{bool} 1210 1211 """ 1212 if self.is_alive(): 1213 if self.has_terminal_session(): 1214 1215 if self.terminal_session.suspend(): 1216 1217 self.running = False 1218 self.suspended = True 1219 self.terminated = False 1220 self.faults = False 1221 self.session_cleanup() 1222 return True 1223 1224 elif self.has_control_session() and self.session_name: 1225 if self.control_session.suspend(session_name=self.session_name): 1226 1227 self.running = False 1228 self.suspended = True 1229 self.terminated = False 1230 self.faulty = False 1231 self.session_cleanup() 1232 return True 1233 1234 else: 1235 raise X2goClientException('cannot suspend session') 1236 1237 else: 1238 self._X2goSession__disconnect() 1239 1240 return False
1241 __suspend = suspend 1242
1243 - def terminate(self):
1244 """\ 1245 Terminate this X2go session. 1246 1247 @return: returns C{True} if terminating the session has been successful, C{False} otherwise 1248 @rtype: C{bool} 1249 1250 """ 1251 if self.is_alive(): 1252 if self.has_terminal_session(): 1253 1254 if self.terminal_session.terminate(): 1255 self.running = False 1256 self.suspended = False 1257 self.terminated = True 1258 self.faulty = False 1259 self.session_cleanup() 1260 return True 1261 1262 elif self.has_control_session() and self.session_name: 1263 if self.control_session.terminate(session_name=self.session_name): 1264 1265 self.running = False 1266 self.suspended = False 1267 self.terminated = True 1268 self.faulty = False 1269 self.session_cleanup() 1270 return True 1271 else: 1272 raise X2goClientException('cannot terminate session') 1273 1274 else: 1275 self._X2goSession__disconnect() 1276 1277 return False
1278 __terminate = terminate 1279
1280 - def get_profile_name(self):
1281 """\ 1282 Retrieve the profile name of this L{X2goSession} instance. 1283 1284 @return: X2go client profile name of the session 1285 @rtype: C{str} 1286 1287 """ 1288 return self.profile_name
1289 __get_profile_name = get_profile_name 1290
1291 - def get_profile_id(self):
1292 """\ 1293 Retrieve the profile ID of this L{X2goSession} instance. 1294 1295 @return: the session profile's id 1296 @rtype: C{str} 1297 1298 """ 1299 return self.profile_id
1300 __get_profile_id = get_profile_id 1301 1302 ### 1303 ### QUERYING INFORMATION 1304 ### 1305
1306 - def session_ok(self):
1307 """\ 1308 Test if this C{X2goSession} is 1309 in a healthy state. 1310 1311 @return: C{BTrue} if session is ok, C{False} otherwise 1312 @rtype: C{bool} 1313 1314 """ 1315 if self.has_terminal_session(): 1316 return self.terminal_session.ok() 1317 return False
1318 __session_ok = session_ok 1319
1321 """\ 1322 Extract color depth from session name. 1323 1324 @return: the session's color depth (as found in the session name) 1325 @rtype: C{str} 1326 1327 """ 1328 return int(self.get_session_name().split('_')[2][2:])
1329 __color_depth_from_session_name = color_depth_from_session_name 1330
1331 - def is_color_depth_ok(self):
1332 """\ 1333 Check if this session will display properly with the local screen's color depth. 1334 1335 @return: C{True} if the session will display on this client screen, False otherwise. If no terminal session is yet registered with this session, C{None} is returned. 1336 @rtype C{bool} 1337 1338 """ 1339 return utils.is_color_depth_ok(depth_session=self.color_depth_from_session_name(), depth_local=utils.local_color_depth()) 1340 __is_color_depth_ok = is_color_depth_ok
1341
1342 - def is_connected(self):
1343 """\ 1344 Test if the L{X2goSession}'s control session is connected to the 1345 remote X2go server. 1346 1347 @return: C{True} if session is connected, C{False} otherwise 1348 @rtype: C{bool} 1349 1350 """ 1351 self.connected = bool(self.control_session and self.control_session.is_connected()) 1352 if not self.connected: 1353 self.running = None 1354 self.suspended = None 1355 self.terminated = None 1356 self.faulty = None 1357 return self.connected
1358 __is_connected = is_connected 1359
1360 - def is_running(self):
1361 """\ 1362 Test if the L{X2goSession}'s terminal session is up and running. 1363 1364 @return: C{True} if session is running, C{False} otherwise 1365 @rtype: C{bool} 1366 1367 """ 1368 if self.is_connected(): 1369 self.running = self.control_session.is_running(self.get_session_name()) 1370 if self.running: 1371 self.suspended = False 1372 self.terminated = False 1373 self.faulty = False 1374 if self.virgin and not self.running: 1375 self.running = None 1376 return self.running
1377 __is_running = is_running 1378
1379 - def is_suspended(self):
1380 """\ 1381 Test if the L{X2goSession}'s terminal session is in suspended state. 1382 1383 @return: C{True} if session is suspended, C{False} otherwise 1384 @rtype: C{bool} 1385 1386 """ 1387 if self.is_connected(): 1388 self.suspended = self.control_session.is_suspended(self.get_session_name()) 1389 if self.suspended: 1390 self.running = False 1391 self.terminated = False 1392 self.faulty = False 1393 if self.virgin and not self.suspended: 1394 self.suspended = None 1395 return self.suspended
1396 __is_suspended = is_suspended 1397
1398 - def has_terminated(self):
1399 """\ 1400 Test if the L{X2goSession}'s terminal session has terminated. 1401 1402 @return: C{True} if session has terminated, C{False} otherwise 1403 @rtype: C{bool} 1404 1405 """ 1406 if self.is_connected(): 1407 self.terminated = not self.virgin and self.control_session.has_terminated(self.get_session_name()) 1408 if self.terminated: 1409 self.running = False 1410 self.suspended = False 1411 self.faulty = False 1412 if self.virgin and not self.terminated: 1413 self.terminated = None 1414 return self.terminated
1415 __has_terminated = has_terminated 1416
1418 """\ 1419 Test if the remote session allows sharing of local folders with the session. 1420 1421 @return: returns C{True} if local folder sharing is available in the remote session 1422 @rtype: C{bool} 1423 1424 """ 1425 if self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders: 1426 if self.is_connected(): 1427 return self.control_session.is_folder_sharing_available() 1428 else: 1429 self.logger('local folder sharing is disabled for this session profile', loglevel=log.loglevel_WARN)
1430
1431 - def share_local_folder(self, local_path=None, folder_name=None):
1432 """\ 1433 Share a local folder with this registered X2go session. 1434 1435 @param local_path: the full path to an existing folder on the local 1436 file system 1437 @type local_path: C{str} 1438 @param folder_name: synonymous to C{local_path} 1439 @type folder_name: C{str} 1440 1441 @return: returns C{True} if the local folder has been successfully mounted within 1442 this X2go session 1443 @rtype: C{bool} 1444 1445 """ 1446 # compat for Python-X2go (<=0.1.1.6) 1447 if folder_name: local_path=folder_name 1448 1449 if self.has_terminal_session(): 1450 if self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders: 1451 if self.terminal_session.share_local_folder(local_path=local_path): 1452 self.shared_folders.append(local_path) 1453 return True 1454 return False 1455 else: 1456 self.logger('local folder sharing is disabled for this session profile', loglevel=log.loglevel_WARN) 1457 else: 1458 raise X2goSessionException('this X2goSession object does not have any associated terminal')
1459 __share_local_folder = share_local_folder 1460
1461 - def unshare_all_local_folders(self, force_all=False):
1462 """\ 1463 Unshare all local folders mounted within this X2go session. 1464 1465 @param force_all: Really unmount _all_ shared folders, including the print spool folder and 1466 the MIME box spool dir (not recommended). 1467 @type force_all: C{bool} 1468 1469 @return: returns C{True} if all local folders could be successfully unmounted 1470 inside this X2go session 1471 @rtype: C{bool} 1472 1473 """ 1474 if self.has_terminal_session(): 1475 if self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders: 1476 if force_all: 1477 self.shared_folders = [] 1478 return self.terminal_session.unshare_all_local_folders() 1479 else: 1480 retval = 0 1481 for _shared_folder in self.shared_folders: 1482 retval = retval | self.terminal_session.unshare_local_folder(_shared_folder) 1483 self.shared_folders = [] 1484 return retval 1485 else: 1486 self.logger('local folder sharing is disabled for this session profile', loglevel=log.loglevel_WARN) 1487 else: 1488 raise X2goSessionException('this X2goSession object does not have any associated terminal') 1489 return False
1490 __unshare_all_local_folders = unshare_all_local_folders 1491
1492 - def unshare_local_folder(self, local_path=None):
1493 """\ 1494 Unshare a local folder that is mounted within this X2go session. 1495 1496 @param local_path: the full path to an existing folder on the local 1497 file system that is mounted in this X2go session and shall be 1498 unmounted 1499 @type local_path: C{str} 1500 @return: returns C{True} if all local folders could be successfully unmounted 1501 inside this X2go session 1502 @rtype: C{bool} 1503 1504 """ 1505 if self.has_terminal_session(): 1506 if self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders and local_path in self.shared_folders: 1507 self.shared_folders.remove(local_path) 1508 return self.terminal_session.unshare_local_folder(local_path=local_path) 1509 else: 1510 self.logger('local folder sharing is disabled for this session profile', loglevel=log.loglevel_WARN) 1511 else: 1512 raise X2goSessionException('this X2goSession object does not have any associated terminal')
1513 __unshare_local_folder = unshare_local_folder 1514
1515 - def get_shared_folders(self):
1516 """\ 1517 Get a list of local folders mounted within this X2go session from this client. 1518 1519 @return: returns a C{list} of those folder names that are mounted with this X2go session. 1520 @rtype: C{list} 1521 1522 """ 1523 return self.shared_folders
1524 __get_shared_folders = get_shared_folders 1525
1526 - def is_locked(self):
1527 """\ 1528 Query session if it is locked by some command being processed. 1529 1530 @return: return C{True} is the session is locked, C{False} if not; returns None, if there is no 1531 control session yet. 1532 @rtype: C{bool} 1533 1534 """ 1535 if self.control_session is not None: 1536 return self.control_session.locked or self.locked 1537 return None
1538
1539 - def session_cleanup(self):
1540 """\ 1541 Clean up X2go session. 1542 1543 """ 1544 # release terminal session's proxy 1545 if self.has_terminal_session(): 1546 self.terminal_session.release_proxy() 1547 1548 # unmount shared folders 1549 try: 1550 self.unshare_all_local_folders() 1551 except X2goSessionException: 1552 pass 1553 1554 # remove client-side session cache 1555 if self.terminated and self.has_terminal_session(): 1556 self.terminal_session.post_terminate_cleanup() 1557 1558 # destroy terminal session 1559 if self.has_terminal_session(): 1560 self.terminal_session.__del__() 1561 1562 self.terminal_session = None
1563