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