Package x2go :: Package backends :: Package terminal :: Module _stdout
[frames] | no frames]

Source Code for Module x2go.backends.terminal._stdout

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2011 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> 
  4  # 
  5  # Python X2go is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 3 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # Python X2go is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with this program; if not, write to the 
 17  # Free Software Foundation, Inc., 
 18  # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 
 19   
 20  """\ 
 21  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  # modules 
 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  # Python X2go modules 
 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  # we hide the default values from epydoc (that's why we transform them to _UNDERSCORE variables) 
 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   
66 -def _rewrite_cmd(cmd, params=None):
67 68 # start with an empty string 69 cmd = cmd or '' 70 71 # find window manager commands 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 # place quot marks around cmd if not empty string 82 if cmd: 83 cmd = '"%s"' % cmd 84 return cmd
85 86
87 -def _rewrite_blanks(cmd):
88 # X2go run command replace X2GO_SPACE_CHAR string with blanks 89 if cmd: 90 cmd = cmd.replace(" ", "X2GO_SPACE_CHAR") 91 return cmd
92 93
94 -class X2goSessionParams(object):
95 """\ 96 The L{X2goSessionParams} class is used to store all parameters that 97 C{X2goTerminalSession} backend objects are constructed with. 98 99 """
100 - def rewrite_session_type(self):
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
157 -class X2goTerminalSessionSTDOUT(object):
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
328 - def __del__(self):
329 self._x2go_tidy_up()
330
331 - def _x2go_tidy_up(self):
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
355 - def _mk_sessions_rootdir(self, d):
356 357 try: 358 os.mkdir(d) 359 except OSError, e: 360 if e.errno == 17: 361 # file exists 362 pass 363 else: 364 raise OSError, e
365
366 - def get_session_name(self):
367 """\ 368 STILL UNDOCUMENTED 369 370 """ 371 return self.session_info.name
372
373 - def start_sound(self):
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 ### PULSEAUDIO 389 ### 390 if os.path.exists(os.path.normpath('%s/.pulse-cookie' % _LOCAL_HOME)): 391 # setup pulse client config file on X2go server 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 # start reverse SSH tunnel for pulse stream 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 ### ARTSD AUDIO 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 ### ESD AUDIO 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 # start reverse SSH tunnel for pulse stream 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 # tunnel has already been started and might simply need a resume call 440 self.reverse_tunnels[self.session_info.name]['snd'][1].resume()
441
442 - def start_sshfs(self):
443 """\ 444 Initialize Paramiko/SSH reverse forwarding tunnel for X2go folder sharing. 445 446 """ 447 # start reverse SSH tunnel for sshfs (folder sharing, printing) 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 # tunnel has already been started and might simply need a resume call 465 self.reverse_tunnels[self.session_info.name]['sshfs'][1].resume()
466
467 - def _x2go_pause_rev_fw_tunnel(self, name):
468 # pause reverse SSH tunnel of name <name> 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
474 - def stop_sound(self):
475 """\ 476 Shutdown (pause) Paramiko/SSH reverse forwarding tunnel for X2go sound. 477 478 """ 479 self._x2go_pause_rev_fw_tunnel('snd')
480
481 - def stop_sshfs(self):
482 """\ 483 Shutdown (pause) Paramiko/SSH reverse forwarding tunnel for X2go folder sharing. 484 485 """ 486 self._x2go_pause_rev_fw_tunnel('sshfs')
487
488 - def start_printing(self):
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
512 - def set_print_action(self, print_action, **kwargs):
513 """\ 514 STILL UNDOCUMENTED 515 516 """ 517 self.print_queue.set_print_action(print_action, logger=self.logger, **kwargs)
518
519 - def stop_printing(self):
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
527 - def get_printing_spooldir(self):
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
554 - def set_mimebox_action(self, mimebox_action, **kwargs):
555 """\ 556 STILL UNDOCUMENTED 557 558 """ 559 self.mimebox_queue.set_mimebox_action(mimebox_action, logger=self.logger, **kwargs)
560
561 - def stop_mimebox(self):
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
569 - def get_mimebox_spooldir(self):
570 """\ 571 Return the server-side mimebox spooldir path. 572 573 """ 574 return '%s/%s' % (self.session_info.remote_container, 'mimebox')
575
576 - def share_local_folder(self, folder_name=None, folder_type='disk'):
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 # _x2go_key_fname must be a UniX path 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
678 - def color_depth(self):
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
688 - def has_command(self, cmd):
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
711 - def run_command(self, cmd=None, env={}):
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 # do not run command when in XDMCP mode... 740 return None 741 742 if 'XSHAD' in cmd: 743 # do not run command when in DESKTOP SHARING mode... 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
770 - def ok(self):
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
781 - def is_running(self):
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
792 - def is_suspended(self):
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
803 - def is_connected(self):
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
813 - def start(self):
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 # if the first line of stdout is a "DEN(Y)" string then we will presume that 851 # we tried to use X2go desktop sharing and the sharing was rejected 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 # local path may be a Windows path, so we use the path separator of the local system 861 self.session_info.local_container = os.path.join(self.params.rootdir, 'S-%s' % self.session_info.name) 862 # remote path is always a UniX path... 863 self.session_info.remote_container = '%s/.x2go/C-%s' % (self.control_session._x2go_remote_home, 864 self.session_info.name, 865 ) 866 867 # let the proxy backend know that we want to define a very special keymap 868 if (self.params.kbtype.endswith('defkeymap') and self.params.kblayout == 'defkeymap'): 869 self.proxy_options.update({'defkeymap': True, }) 870 871 # set up SSH tunnel for X11 graphical elements 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
883 - def resume(self):
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 # local path may be a Windows path, so we use the path separator of the local system 918 self.session_info.local_container = os.path.join(self.params.rootdir, 'S-%s' % self.session_info.name) 919 # remote path is always a UniX path... 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 # on a session resume the user name comes in as a user ID. We have to translate this... 925 self.session_info.username = self.control_session.remote_username() 926 return self.ok()
927
928 - def suspend(self):
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 # TODO: check if session has really suspended 940 _ret = True 941 942 return _ret
943
944 - def terminate(self):
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 # TODO: check if session has really suspended 956 _ret = True 957 958 return _ret
959
960 - def release_proxy(self):
961 """\ 962 STILL UNDOCUMENTED 963 964 """ 965 if self.proxy is not None: 966 self.proxy.__del__()
967