1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 """\
21 X2goTerminalSession class - core functions for handling your individual X2go sessions.
22
23 This backend handles X2go server implementations that respond with session infos
24 via server-side STDOUT and use NX3 as graphical proxy.
25
26 """
27 __NAME__ = 'x2goterminalsession-pylib'
28
29
30 import os
31 import sys
32 import types
33 import gevent
34 import threading
35 import signal
36 import cStringIO
37 import copy
38
39
40 import x2go.rforward as rforward
41 import x2go.sftpserver as sftpserver
42 import x2go.printqueue as printqueue
43 import x2go.mimebox as mimebox
44 import x2go.log as log
45 import x2go.defaults as defaults
46 import x2go.utils as utils
47 import x2go.x2go_exceptions as x2go_exceptions
48
49 from x2go.cleanup import x2go_cleanup
50
51
52 from x2go.defaults import X2GOCLIENT_OS as _X2GOCLIENT_OS
53 from x2go.defaults import LOCAL_HOME as _LOCAL_HOME
54 from x2go.defaults import CURRENT_LOCAL_USER as _CURRENT_LOCAL_USER
55 from x2go.defaults import X2GO_CLIENT_ROOTDIR as _X2GO_CLIENT_ROOTDIR
56 from x2go.defaults import X2GO_SESSIONS_ROOTDIR as _X2GO_SESSIONS_ROOTDIR
57 from x2go.defaults import X2GO_GENERIC_APPLICATIONS as _X2GO_GENERIC_APPLICATIONS
58
59 from x2go.backends.info import X2goServerSessionInfo as _X2goServerSessionInfo
60 from x2go.backends.info import X2goServerSessionList as _X2goServerSessionList
61 from x2go.backends.proxy import X2goProxy as _X2goProxy
62 from x2go.backends.printing import X2goClientPrinting as _X2goClientPrinting
63
64 _local_color_depth = utils.local_color_depth()
65
67
68
69 cmd = cmd or ''
70
71
72 if cmd in defaults.X2GO_DESKTOPSESSIONS.keys():
73 cmd = defaults.X2GO_DESKTOPSESSIONS[cmd]
74
75 if (cmd == 'RDP') and (type(params) == X2goSessionParams):
76 if params.geometry == 'fullscreen':
77 cmd = 'rdesktop -f -N %s %s -a %s' % (params.rdp_options, params.rdp_server, params.depth)
78 else:
79 cmd = 'rdesktop -g %s -N %s %s -a %s' % (params.geometry, params.rdp_options, params.rdp_server, params.depth)
80
81
82 if cmd:
83 cmd = '"%s"' % cmd
84 return cmd
85
86
88
89 if cmd:
90 cmd = cmd.replace(" ", "X2GO_SPACE_CHAR")
91 return cmd
92
93
95 """\
96 The L{X2goSessionParams} class is used to store all parameters that
97 C{X2goTerminalSession} backend objects are constructed with.
98
99 """
101 """\
102 Rewrite the X2go session type, so that the X2go server
103 can understand it (C{desktop} -> C{D}).
104
105 Also if the object's C{command} property is a known window
106 manager, the session type will be set to 'D'
107 (i.e. desktop).
108
109 @return: 'D' if session should probably a desktop session,
110 'R' (for rootless) else
111 @rtype: str
112
113 """
114 session_type = self.session_type
115 cmd = self.cmd
116
117 if session_type in ("D", "desktop"):
118 self.session_type = 'D'
119 return
120 elif session_type in ("S", "shared", "shadow"):
121 self.session_type = 'S'
122 return
123 elif cmd:
124 if cmd == 'RDP':
125 self.session_type = 'R'
126 return
127 elif cmd.startswith('rdesktop'):
128 self.session_type = 'R'
129 return
130 elif cmd == 'XDMCP':
131 self.session_type = 'D'
132 return
133 elif cmd in defaults.X2GO_DESKTOPSESSIONS.keys():
134 self.session_type = 'D'
135 return
136 elif os.path.basename(cmd) in defaults.X2GO_DESKTOPSESSIONS.values():
137 self.session_type = 'D'
138 return
139 self.session_type = 'R'
140
141 - def update(self, properties_to_be_updated={}):
142 """\
143 Update all properties in the object L{X2goSessionParams} object from
144 the passed on dictionary.
145
146 @param properties_to_be_updated: a dictionary with L{X2goSessionParams}
147 property names as keys und their values to be update in
148 L{X2goSessionParams} object.
149 @type properties_to_be_updated: dict
150
151 """
152 for key in properties_to_be_updated.keys():
153 setattr(self, key, properties_to_be_updated[key] or '')
154 self.rewrite_session_type()
155
156
158 """\
159 Class for managing X2go sessions on a remote X2go server via Paramiko/SSH.
160 With the L{X2goTerminalSessionSTDOUT} class you can start new X2go sessions, resume suspended
161 sessions or suspend resp. terminate currently running sessions on a
162 connected X2go server.
163
164 When suspending or terminating sessions there are two possible ways:
165
166 1. Initialize an X2go session object, start a new session (or resume)
167 and use the L{X2goTerminalSessionSTDOUT.suspend()} or L{X2goTerminalSessionSTDOUT.terminate()} method
168 to suspend/terminate the current session object.
169 2. Alternatively, you can pass a session name to L{X2goTerminalSessionSTDOUT.suspend()}
170 or L{X2goTerminalSessionSTDOUT.terminate()}. If a session of this name exists on the
171 X2go server the respective action will be performed on the session.
172
173 An L{X2goTerminalSessionSTDOUT} object uses two main data structure classes:
174
175 - L{X2goSessionParams}: stores all parameters that have been passed to the
176 constructor method.
177
178 - C{X2goServerSessionInfo} backend class: when starting or resuming a session, an object of this class
179 will be used to store all information retrieved from the X2go server.
180
181
182 """
183 - def __init__(self, control_session, session_info=None,
184 geometry="800x600", depth=_local_color_depth, link="adsl", pack="16m-jpeg-9",
185 cache_type="unix-kde",
186 keyboard='', kblayout='null', kbtype='null/null',
187 session_type="application", snd_system='pulse', snd_port=4713, cmd=None,
188 rdp_server=None, rdp_options=None,
189 xdmcp_server=None,
190 convert_encoding=False, server_encoding='UTF-8', client_encoding='UTF-8',
191 rootdir=None,
192 profile_name='UNKNOWN', profile_id=utils._genSessionProfileId(),
193 print_action=None, print_action_args={},
194 info_backend=_X2goServerSessionInfo,
195 list_backend=_X2goServerSessionList,
196 proxy_backend=_X2goProxy, proxy_options={},
197 printing_backend=_X2goClientPrinting,
198 client_rootdir=os.path.join(_LOCAL_HOME, _X2GO_CLIENT_ROOTDIR),
199 sessions_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SESSIONS_ROOTDIR),
200 session_instance=None,
201 logger=None, loglevel=log.loglevel_DEFAULT):
202 """\
203 Initialize an X2go session. With the L{X2goTerminalSessionSTDOUT} class you can start
204 new X2go sessions, resume suspended sessions or suspend resp. terminate
205 currently running sessions on a connected X2go server.
206
207 @param geometry: screen geometry of the X2go session. Can be either C{<width>x<height>}
208 or C{fullscreen}
209 @type geometry: str
210 @param depth: color depth in bits (common values: C{16}, C{24})
211 @type depth: int
212 @param link: network link quality (either one of C{modem}, C{isdn}, C{adsl}, C{wan} or C{lan})
213 @type link: str
214 @param pack: compression method for NX based session proxying
215 @type pack: str
216 @param cache_type: a dummy parameter that is passed to the L{X2goProxyBASE}. In NX Proxy
217 (class C{X2goProxyNX3}) this originally is the session name. With X2go it
218 defines the name of the NX cache directory. Best is to leave it untouched.
219 @type cache_type: str
220 @param kblayout: keyboard layout, e.g. C{us} (default), C{de}, C{fr}, ...
221 @type kblayout: str
222 @param kbtype: keyboard type, e.g. C{pc105/us} (default), C{pc105/de}, ...
223 @type kbtype: str
224 @param session_type: either C{desktop}, C{application} (rootless session) or C{shared}
225 @type session_type: str
226 @param snd_system: sound system to be used on server (C{none}, C{pulse} (default),
227 C{arts} (obsolete) or C{esd})
228 @type snd_system: str
229 @param cmd: command to be run on X2go server after session start (only used
230 when L{X2goTerminalSessionSTDOUT.start()} is called, ignored on resume, suspend etc.
231 @type cmd: str
232 @param rootdir: X2go session directory, normally C{~/.x2go}
233 @type rootdir: str
234 @param info_backend: backend for handling storage of server session information
235 @type info_backend: C{X2goServerSessionInfo*} instance
236 @param list_backend: backend for handling storage of session list information
237 @type list_backend: C{X2goServerSessionList*} instance
238 @param proxy_backend: backend for handling the X-proxy connections
239 @type proxy_backend: C{X2goProxy*} instance
240 @param print_action: either a print action short name (PDFVIEW, PDFSAVE, PRINT, PRINTCMD) or the
241 resp. C{X2goPrintActionXXX} class (where XXX equals one of the given short names)
242 @type print_action: str or class
243 @param print_action_args: optional arguments for a given print_action (for further info refer to
244 L{X2goPrintActionPDFVIEW}, L{X2goPrintActionPDFSAVE}, L{X2goPrintActionPRINT} and L{X2goPrintActionPRINTCMD})
245 @type print_action_args: dict
246 @param proxy_options: a set of very C{X2goProxy*} backend specific options; any option that is not known
247 to the C{X2goProxy*} backend will simply be ignored
248 @type proxy_options: C{dict}
249 @param logger: you can pass an L{X2goLogger} object to the
250 L{X2goTerminalSessionSTDOUT} constructor
251 @type logger: L{X2goLogger} instance
252 @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
253 constructed with the given loglevel
254 @type loglevel: int
255
256 """
257 self.proxy = None
258 self.proxy_subprocess = None
259 self.proxy_options = proxy_options
260
261 self.active_threads = []
262 self.reverse_tunnels = {}
263
264 self.print_queue = None
265 self.mimebox_queue = None
266
267 if logger is None:
268 self.logger = log.X2goLogger(loglevel=loglevel)
269 else:
270 self.logger = copy.deepcopy(logger)
271 self.logger.tag = __NAME__
272
273 self.control_session = control_session
274 self.reverse_tunnels = self.control_session.get_transport().reverse_tunnels
275
276 self.client_rootdir = client_rootdir
277 self.sessions_rootdir = sessions_rootdir
278
279 self.params = X2goSessionParams()
280
281 self.params.geometry = str(geometry)
282 self.params.link = str(link)
283 self.params.pack = str(pack)
284 self.params.cache_type = str(cache_type)
285 self.params.session_type = str(session_type)
286 self.params.keyboard = str(keyboard)
287 self.params.kblayout = str(kblayout)
288 self.params.kbtype = str(kbtype)
289 self.params.snd_system = str(snd_system)
290 self.params.cmd = str(cmd)
291 self.params.depth = str(depth)
292
293 self.params.rdp_server = str(rdp_server)
294 self.params.rdp_options = str(rdp_options)
295 self.params.xdmcp_server = str(xdmcp_server)
296
297 self.params.convert_encoding = convert_encoding
298 self.params.client_encoding = str(client_encoding)
299 self.params.server_encoding = str(server_encoding)
300
301 self.params.rootdir = (type(rootdir) is types.StringType) and rootdir or self.sessions_rootdir
302 self.params.update()
303
304 self.profile_name = profile_name
305 self.proxy_backend = proxy_backend
306
307 self.snd_port = snd_port
308 self.print_action = print_action
309 self.print_action_args = print_action_args
310 self.printing_backend = printing_backend
311 self.session_instance = session_instance
312 if self.session_instance:
313 self.client_instance = self.session_instance.client_instance
314 else:
315 self.client_instance = None
316
317 self._mk_sessions_rootdir(self.params.rootdir)
318
319 self.session_info = session_info
320 if self.session_info is not None:
321 if self.session_info.name:
322 self.session_info.local_container = os.path.join(self.params.rootdir, 'S-%s' % self.session_info.name)
323 else:
324 raise X2goTerminalSessionException('no valid session info availble')
325 else:
326 self.session_info = info_backend()
327
330
332
333 self.release_proxy()
334
335 try:
336 if self.control_session.get_transport() is not None:
337 try:
338 for _tunnel in [ _tun[1] for _tun in self.reverse_tunnels[self.session_info.name].values() ]:
339 if _tunnel is not None:
340 _tunnel.__del__()
341 except KeyError:
342 pass
343
344 if self.print_queue is not None:
345 self.print_queue.__del__()
346
347 if self.mimebox_queue is not None:
348 self.mimebox_queue.__del__()
349
350 except AttributeError:
351 pass
352
353 self.session_info.clear()
354
356
357 try:
358 os.mkdir(d)
359 except OSError, e:
360 if e.errno == 17:
361
362 pass
363 else:
364 raise OSError, e
365
372
374 """\
375 Initialize Paramiko/SSH reverse forwarding tunnel for X2go sound.
376
377 Currently supported audio protocols:
378
379 - PulseAudio
380 - Esound
381
382 """
383 _tunnel = None
384 if self.reverse_tunnels[self.session_info.name]['snd'][1] is None:
385 if self.params.snd_system == 'pulse':
386 self.logger('initializing PulseAudio sound support in X2go session', loglevel=log.loglevel_INFO)
387
388
389
390 if os.path.exists(os.path.normpath('%s/.pulse-cookie' % _LOCAL_HOME)):
391
392 cmd_line = "echo 'default-server=127.0.0.1:%s'>%s/.pulse-client.conf;" % (self.session_info.snd_port, self.session_info.remote_container) + \
393 "echo 'cookie-file=%s/.pulse-cookie'>>%s/.pulse-client.conf" % (self.session_info.remote_container, self.session_info.remote_container)
394 (stdin, stdout, stderr) = self.control_session._x2go_exec_command(cmd_line)
395
396 self.control_session._x2go_sftp_put(local_path='%s/.pulse-cookie' % _LOCAL_HOME, remote_path='%s/.pulse-cookie' % self.session_info.remote_container)
397
398
399 _tunnel = rforward.X2goRevFwTunnel(server_port=self.session_info.snd_port,
400 remote_host='127.0.0.1',
401 remote_port=self.snd_port,
402 ssh_transport=self.control_session.get_transport(),
403 session_instance=self.session_instance,
404 logger=self.logger
405 )
406 else:
407 if self.client_instance:
408 self.client_instance.HOOK_on_sound_tunnel_failed(profile_name=self.profile_name, session_name=self.session_info.name)
409 elif self.params.snd_system == 'arts':
410
411
412
413 self.logger('the ArtsD sound server (as in KDE3) is obsolete and will not be supported by Python X2go...', loglevel=log.loglevel_WARNING)
414
415 elif self.params.snd_system == 'esd':
416
417
418
419
420 self.logger('initializing ESD sound support in X2go session', loglevel=log.loglevel_INFO)
421 self.control_session._x2go_sftp_put(local_path='%s/.esd_auth' % _LOCAL_HOME, remote_path='%s/.esd_auth' % self.control_session._x2go_remote_home)
422
423
424 _tunnel = rforward.X2goRevFwTunnel(server_port=self.session_info.snd_port,
425 remote_host='127.0.0.1',
426 remote_port=self.snd_port,
427 ssh_transport=self.control_session.get_transport(),
428 session_instance=self.session_instance,
429 logger=self.logger
430 )
431
432
433 if _tunnel is not None:
434 self.reverse_tunnels[self.session_info.name]['snd'] = (self.session_info.snd_port, _tunnel)
435 _tunnel.start()
436 self.active_threads.append(_tunnel)
437
438 else:
439
440 self.reverse_tunnels[self.session_info.name]['snd'][1].resume()
441
443 """\
444 Initialize Paramiko/SSH reverse forwarding tunnel for X2go folder sharing.
445
446 """
447
448 ssh_transport = self.control_session.get_transport()
449 if self.reverse_tunnels[self.session_info.name]['sshfs'][1] is None:
450
451 _tunnel = sftpserver.X2goRevFwTunnelToSFTP(server_port=self.session_info.sshfs_port,
452 ssh_transport=ssh_transport,
453 auth_key=self.control_session._x2go_session_auth_rsakey,
454 session_instance=self.session_instance,
455 logger=self.logger
456 )
457
458 if _tunnel is not None:
459 self.reverse_tunnels[self.session_info.name]['sshfs'] = (self.session_info.sshfs_port, _tunnel)
460 _tunnel.start()
461 self.active_threads.append(_tunnel)
462
463 else:
464
465 self.reverse_tunnels[self.session_info.name]['sshfs'][1].resume()
466
468
469 ssh_transport = self.get_transport()
470 _tunnel = self.reverse_tunnels[self.session_info.name][name][1]
471 if _tunnel is not None:
472 _tunnel.pause()
473
475 """\
476 Shutdown (pause) Paramiko/SSH reverse forwarding tunnel for X2go sound.
477
478 """
479 self._x2go_pause_rev_fw_tunnel('snd')
480
482 """\
483 Shutdown (pause) Paramiko/SSH reverse forwarding tunnel for X2go folder sharing.
484
485 """
486 self._x2go_pause_rev_fw_tunnel('sshfs')
487
489 """\
490 Initialize X2go print spooling.
491
492 """
493 if self.session_info.username not in self.control_session._x2go_remote_group('x2goprint'):
494 raise x2go_exceptions.X2goUserException('remote user %s is not member of X2go server group x2goprint' % self.session_info.username)
495
496 spool_dir = os.path.join(self.session_info.local_container, 'spool')
497 if not os.path.exists(spool_dir):
498 os.mkdir(spool_dir)
499 self.share_local_folder(folder_name=spool_dir, folder_type='spool')
500 self.print_queue = printqueue.X2goPrintQueue(profile_name=self.profile_name,
501 session_name=self.session_info.name,
502 spool_dir=spool_dir,
503 print_action=self.print_action,
504 print_action_args=self.print_action_args,
505 client_instance=self.client_instance,
506 printing_backend=self.printing_backend,
507 logger=self.logger,
508 )
509 self.print_queue.start()
510 self.active_threads.append(self.print_queue)
511
518
520 """\
521 Shutdown (pause) the X2go Print Queue thread.
522
523 """
524 if self.print_queue is not None:
525 self.print_queue.pause()
526
528 """\
529 Return the server-side printing spooldir path.
530
531 """
532 return '%s/%s' % (self.session_info.remote_container, 'spool')
533
534 - def start_mimebox(self, mimebox_extensions=[], mimebox_action=None):
535 """\
536 Initialize X2go mimebox handling.
537
538 """
539 mimebox_dir = os.path.join(self.session_info.local_container, 'mimebox')
540 if not os.path.exists(mimebox_dir):
541 os.mkdir(mimebox_dir)
542 self.share_local_folder(folder_name=mimebox_dir, folder_type='mimebox')
543 self.mimebox_queue = mimebox.X2goMIMEboxQueue(profile_name=self.profile_name,
544 session_name=self.session_info.name,
545 mimebox_dir=mimebox_dir,
546 mimebox_extensions=mimebox_extensions,
547 mimebox_action=mimebox_action,
548 client_instance=self.client_instance,
549 logger=self.logger,
550 )
551 self.mimebox_queue.start()
552 self.active_threads.append(self.mimebox_queue)
553
560
562 """\
563 Shutdown (pause) the X2go MIME box Queue thread.
564
565 """
566 if self.mimebox_queue is not None:
567 self.mimebox_queue.pause()
568
570 """\
571 Return the server-side mimebox spooldir path.
572
573 """
574 return '%s/%s' % (self.session_info.remote_container, 'mimebox')
575
577 """\
578 Share a local folder with the X2go session.
579
580 @param folder_name: the full path to an existing folder on the local
581 file system
582 @type folder_name: str
583 @param folder_type: one of 'disk' (a folder on your local hard drive), 'rm' (removeable device),
584 'cdrom' (CD/DVD Rom) or 'spool' (for X2go print spooling)
585 @type folder_type: str
586
587 @return: returns C{True} if the local folder has been successfully mounted within the X2go server session
588 @rtype: bool
589
590 """
591 if self.session_info.username not in self.control_session._x2go_remote_group('fuse'):
592 raise x2go_exceptions.X2goUserException('remote user %s is not member of X2go server group fuse' % self.session_info.username)
593
594 if folder_name is None:
595 self.logger('no folder name given...', log.loglevel_WARN)
596 return False
597
598 if type(folder_name) not in (types.StringType, types.UnicodeType):
599 self.logger('folder name needs to be of type StringType...', log.loglevel_WARN)
600 return False
601
602 if not os.path.exists(folder_name):
603 self.logger('local folder does not exist: %s' % folder_name, log.loglevel_WARN)
604 return False
605
606 folder_name = os.path.normpath(folder_name)
607 self.logger('sharing local folder: %s' % folder_name, log.loglevel_INFO)
608
609 _auth_rsakey = self.control_session._x2go_session_auth_rsakey
610 _host_rsakey = defaults.RSAHostKey
611
612 _tmp_io_object = cStringIO.StringIO()
613 _auth_rsakey.write_private_key(_tmp_io_object)
614 _tmp_io_object.write('----BEGIN RSA IDENTITY----')
615 _tmp_io_object.write('%s %s' % (_host_rsakey.get_name(),_host_rsakey.get_base64(),))
616
617
618 _x2go_key_fname = '%s/%s/%s' % (os.path.dirname(self.session_info.remote_container), 'ssh', 'key.z%s' % self.session_info.agent_pid)
619 _x2go_key_bundle = _tmp_io_object.getvalue()
620
621 self.control_session._x2go_sftp_write(_x2go_key_fname, _x2go_key_bundle)
622
623 _convert_encoding = self.params.convert_encoding
624 _client_encoding = self.params.client_encoding
625 _server_encoding = self.params.server_encoding
626
627 if _X2GOCLIENT_OS == 'Windows':
628 folder_name = folder_name.replace('\\', '/')
629 folder_name = folder_name.replace(':', '')
630 folder_name = '/windrive/%s' % folder_name
631 _convert_encoding = True
632 _client_encoding = 'WINDOWS-1252'
633
634 if _convert_encoding:
635 export_iconv_settings = 'export X2GO_ICONV=modules=iconv,from_code=%s,to_code=%s &&' % (_client_encoding, _server_encoding)
636 else:
637 export_iconv_settings = ''
638
639 if folder_type == 'disk':
640
641 cmd_line = [ '%s export HOSTNAME &&' % export_iconv_settings,
642 'x2gomountdirs',
643 'dir',
644 str(self.session_info.name),
645 _CURRENT_LOCAL_USER,
646 _x2go_key_fname,
647 '%s__REVERSESSH_PORT__%s; ' % (folder_name, self.session_info.sshfs_port),
648 'rm -f %s %s.ident' % (_x2go_key_fname, _x2go_key_fname),
649 ]
650
651 elif folder_type == 'spool':
652
653 cmd_line = [ '%s export HOSTNAME &&' % export_iconv_settings,
654 'x2gomountdirs',
655 'dir',
656 str(self.session_info.name),
657 _CURRENT_LOCAL_USER,
658 _x2go_key_fname,
659 '%s__PRINT_SPOOL___REVERSESSH_PORT__%s; ' % (folder_name, self.session_info.sshfs_port),
660 'rm -f %s %s.ident' % (_x2go_key_fname, _x2go_key_fname),
661 ]
662
663 elif folder_type == 'mimebox':
664
665 cmd_line = [ '%s export HOSTNAME &&' % export_iconv_settings,
666 'x2gomountdirs',
667 'dir',
668 str(self.session_info.name),
669 _CURRENT_LOCAL_USER,
670 _x2go_key_fname,
671 '%s__MIMEBOX_SPOOL___REVERSESSH_PORT__%s; ' % (folder_name, self.session_info.sshfs_port),
672 'rm -f %s %s.ident' % (_x2go_key_fname, _x2go_key_fname),
673 ]
674
675 (stdin, stdout, stderr) = self.control_session._x2go_exec_command(cmd_line)
676 self.logger('x2gomountdirs output is : %s' % stdout.read().split('\n'), log.loglevel_NOTICE)
677
679 """\
680 Retrieve the session's color depth.
681
682 @return: the session's color depth
683 @rtype: C{int}
684
685 """
686 return self.params.depth
687
689 """\
690 Verify if the command <cmd> exists on the X2go server.
691
692 """
693 cmd = cmd.strip('"').strip('"')
694 if cmd.find('RDP') != -1:
695 cmd = 'rdesktop'
696
697 if cmd in _X2GO_GENERIC_APPLICATIONS:
698 return True
699 elif 'XSHAD' in cmd:
700 return True
701 elif cmd:
702 test_cmd = 'which %s && echo OK' % os.path.basename(cmd.split()[0])
703
704 if test_cmd:
705 (stdin, stdout, stderr) = self.control_session._x2go_exec_command([test_cmd])
706 _stdout = stdout.read()
707 return _stdout.find('OK') != -1
708 else:
709 return False
710
712 """\
713 Run a command in this session.
714
715 After L{X2goTerminalSessionSTDOUT.start()} has been called
716 one or more commands can be executed with L{X2goTerminalSessionSTDOUT.run_command()}
717 within the current X2go session.
718
719 @param cmd: Command to be run
720 @type cmd: str
721
722 @return: stdout.read() and stderr.read() as returned by the run command
723 on the X2go server
724 @rtype: tuple of str
725
726 """
727 if not self.has_command(_rewrite_cmd(self.params.cmd)):
728 if self.client_instance:
729 self.client_instance.HOOK_no_such_command(profile_name=self.profile_name, session_name=self.session_info.name, cmd=self.params.cmd)
730 return False
731
732 if cmd in ("", None):
733 if self.params.cmd is None:
734 cmd = 'TERMINAL'
735 else:
736 cmd = self.params.cmd
737
738 if cmd == 'XDMCP':
739
740 return None
741
742 if 'XSHAD' in cmd:
743
744 return None
745
746 self.params.update({'cmd': cmd})
747
748 cmd_line = [ "setsid x2goruncommand",
749 str(self.session_info.display),
750 str(self.session_info.agent_pid),
751 str(self.session_info.name),
752 str(self.session_info.snd_port),
753 _rewrite_blanks(_rewrite_cmd(self.params.cmd, params=self.params)),
754 str(self.params.snd_system),
755 str(self.params.session_type),
756 ">& /dev/null & exit",
757 ]
758
759 if self.params.snd_system == 'pulse':
760 cmd_line = [ 'PULSE_CLIENTCONFIG=%s/.pulse-client.conf' % self.session_info.remote_container ] + cmd_line
761
762 if env:
763 for env_var in env.keys():
764 cmd_line = [ '%s=%s' % (env_var, env[env_var]) ] + cmd_line
765
766 (stdin, stdout, stderr) = self.control_session._x2go_exec_command(cmd_line)
767
768 return stdout.read(), stderr.read()
769
771 """\
772 Returns C{True} if this X2go session is up and running,
773 C{False} else
774
775 @return: X2go session OK?
776 @rtype: bool
777
778 """
779 return bool(self.session_info.name and self.proxy.ok())
780
782 """\
783 Returns C{True} if this X2go session is in running state,
784 C{False} else.
785
786 @return: X2go session running?
787 @rtype: bool
788
789 """
790 return self.session_info.is_running()
791
793 """\
794 Returns C{True} if this X2go session is in suspended state,
795 C{False} else.
796
797 @return: X2go session suspended?
798 @rtype: bool
799
800 """
801 return self.session_info.is_suspended()
802
804 """\
805 Returns C{True} if this X2go session's Paramiko/SSH transport is
806 connected/authenticated, C{False} else.
807
808 @return: X2go session connected?
809 @rtype: bool
810 """
811 return self.control_session.is_connected()
812
814 """\
815 Start a new X2go session.
816
817 The L{X2goTerminalSession.start()} method accepts any parameter
818 that can be passed to the class constructor.
819
820 """
821 if not self.has_command(_rewrite_cmd(self.params.cmd)):
822 if self.client_instance:
823 self.client_instance.HOOK_no_such_command(profile_name=self.profile_name, session_name=self.session_info.name, cmd=self.params.cmd)
824 return False
825
826 setkbd = "0"
827 if self.params.kblayout or self.params.kbtype:
828 setkbd = "1"
829
830 cmd_line = [ "x2gostartagent",
831 str(self.params.geometry),
832 str(self.params.link),
833 str(self.params.pack),
834 str(self.params.cache_type+'-depth_'+self.params.depth),
835 str(self.params.kblayout),
836 str(self.params.kbtype),
837 str(setkbd),
838 str(self.params.session_type),
839 self.params.cmd,
840 ]
841
842 if self.params.cmd == 'XDMCP' and self.params.xdmcp_server:
843 cmd_line = ['X2GOXDMCP=%s' % self.params.xdmcp_server] + cmd_line
844
845 (stdin, stdout, stderr) = self.control_session._x2go_exec_command(cmd_line)
846
847 _stdout = stdout.read()
848 _stderr = stderr.read()
849
850
851
852 if "ACCESS DENIED" in _stderr and "XSHAD" in _stderr:
853 raise x2go_exceptions.X2goDesktopSharingException('X2go desktop sharing has been denied by the remote user')
854
855 self.session_info.initialize(_stdout,
856 username=self.control_session.remote_username(),
857 hostname=self.control_session.get_transport().getpeername(),
858 )
859
860
861 self.session_info.local_container = os.path.join(self.params.rootdir, 'S-%s' % self.session_info.name)
862
863 self.session_info.remote_container = '%s/.x2go/C-%s' % (self.control_session._x2go_remote_home,
864 self.session_info.name,
865 )
866
867
868 if (self.params.kbtype.endswith('defkeymap') and self.params.kblayout == 'defkeymap'):
869 self.proxy_options.update({'defkeymap': True, })
870
871
872 self.proxy = self.proxy_backend(session_info=self.session_info,
873 ssh_transport=self.control_session.get_transport(),
874 sessions_rootdir=self.sessions_rootdir,
875 session_instance=self.session_instance,
876 proxy_options=self.proxy_options,
877 logger=self.logger)
878 self.proxy_subprocess = self.proxy.start_proxy()
879 self.active_threads.append(self.proxy)
880
881 return self.ok()
882
884 """\
885 Resume a running/suspended X2go session.
886
887 The L{X2goTerminalSessionSTDOUT.resume()} method accepts any parameter
888 that can be passed to the class constructor.
889
890 @return: True if the session could be successfully resumed
891 @rtype: bool
892
893 """
894 setkbd = "0"
895 if self.params.kblayout or self.params.kbtype:
896 setkbd = "1"
897
898 cmd_line = [ "x2goresume-session", self.session_info.name,
899 self.params.geometry,
900 self.params.link,
901 self.params.pack,
902 self.params.kblayout,
903 self.params.kbtype,
904 setkbd,
905 ]
906
907 (stdin, stdout, stderr) = self.control_session._x2go_exec_command(cmd_line)
908
909 self.proxy = self.proxy_backend(session_info=self.session_info,
910 ssh_transport=self.control_session.get_transport(),
911 sessions_rootdir=self.sessions_rootdir,
912 session_instance=self.session_instance,
913 logger=self.logger
914 )
915 self.proxy_subprocess = self.proxy.start_proxy()
916
917
918 self.session_info.local_container = os.path.join(self.params.rootdir, 'S-%s' % self.session_info.name)
919
920 self.session_info.remote_container = '%s/.x2go/C-%s' % (self.control_session._x2go_remote_home,
921 self.session_info.name,
922 )
923 self.params.depth = self.session_info.name.split('_')[2][2:]
924
925 self.session_info.username = self.control_session.remote_username()
926 return self.ok()
927
929 """\
930 Suspend this X2go session terminal.
931
932 @return: True if the session terminal could be successfully suspended
933 @rtype: bool
934
935 """
936 self.control_session.suspend(session_name=self.session_info.name)
937 self.release_proxy()
938
939
940 _ret = True
941
942 return _ret
943
945 """\
946 Terminate this X2go session.
947
948 @return: True if the session terminal could be successfully terminate
949 @rtype: bool
950
951 """
952 self.control_session.terminate(session_name=self.session_info.name)
953 self.release_proxy()
954
955
956 _ret = True
957
958 return _ret
959
961 """\
962 STILL UNDOCUMENTED
963
964 """
965 if self.proxy is not None:
966 self.proxy.__del__()
967