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