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