[X2Go-Commits] python-x2go.git - twofactorauth (branch) updated: 0.1.1.4-130-g0eff893

X2Go dev team git-admin at x2go.org
Sat Sep 14 15:57:16 CEST 2013


The branch, twofactorauth has been updated
       via  0eff893ffaa6c3358e4ca2184bebe5b471d529f0 (commit)
      from  f2e8361dc164f7ae5215745fe7d56ac9cf25fca0 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 debian/changelog                  |    1 +
 x2go/backends/control/_stdout.py  |   43 +++++++++++++++-
 x2go/backends/info/_stdout.py     |    5 ++
 x2go/backends/terminal/_stdout.py |  103 ++++++++++++++++++++++++++++++-------
 x2go/client.py                    |   56 +++++++++++++++++++-
 x2go/defaults.py                  |    3 +-
 x2go/registry.py                  |   35 ++++++++++++-
 x2go/session.py                   |   94 ++++++++++++++++++++++++++++++---
 x2go/utils.py                     |   10 ++--
 9 files changed, 313 insertions(+), 37 deletions(-)

The diff of changes is:
diff --git a/debian/changelog b/debian/changelog
index 65571f2..8097dc9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -39,6 +39,7 @@ python-x2go (0.1.2.0-0~x2go1) UNRELEASED; urgency=low
     - Amend list of default session options.
     - Update list of unsupported session options.
     - Retrieve feature list from X2Go server per session.
+    - Add published applications support.
   * Depend on python-xlib.
 
  -- Mike Gabriel <mike.gabriel at das-netzwerkteam.de>  Sat, 28 Sep 2012 01:44:21 +0100
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index fc345d9..6b3dd1f 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -141,6 +141,8 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         self.sessions_rootdir = sessions_rootdir
         self.ssh_rootdir = ssh_rootdir
 
+        self._published_applications_menu = None
+
         paramiko.SSHClient.__init__(self, *args, **kwargs)
         if self.add_to_known_hosts:
             self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -591,6 +593,39 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             return True
         return False
 
+    def get_published_applications(self):
+        """\
+        Retrieve the menu tree of published applications from X2Go server.
+
+        """
+        if 'X2GO_PUBLISHED_APPLICATIONS' in self._x2go_server_features:
+            if self._published_applications_menu is None:
+                self.logger('querying server (%s) for list of published applications' % self.profile_name, loglevel=log.loglevel_NOTICE)
+                (stdin, stdout, stderr) = self._x2go_exec_command('which x2gogetapps >/dev/null && x2gogetapps')
+                _raw_menu_items = stdout.read().split('</desktop>\n')
+                _raw_menu_items = [ i.replace('<desktop>\n', '') for i in _raw_menu_items ]
+                _menu = []
+                for _raw_menu_item in _raw_menu_items:
+                    if '<icon>\n' in _raw_menu_item and '</icon>' in _raw_menu_item:
+                        _menu_item = _raw_menu_item.split('<icon>\n')[0] + _raw_menu_item.split('</icon>\n')[1]
+                        _icon_base64 = _raw_menu_item.split('<icon>\n')[1].split('</icon>\n')[0].replace('\n', '')
+                    else:
+                        _menu_item = _raw_menu_item
+                        _icon_base64 = None
+                    if _menu_item:
+                        _menu.append({ 'desktop': _menu_item, 'icon': _icon_base64, })
+                        _menu_item = None
+                        _icon_base64 = None
+
+                self._published_applications_menu = _menu
+                self.logger('published applications query for %s finished' % self.profile_name, loglevel=log.loglevel_NOTICE)
+                return self._published_applications_menu
+            else:
+                return self._published_applications_menu
+        else:
+            # FIXME: ignoring the absence of the published applications feature for now, handle it appropriately later
+            pass
+
     def start(self, **kwargs):
         """\
         Start a new X2Go session. 
@@ -826,14 +861,18 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
             return _listsessions
 
-    def clean_sessions(self, destroy_terminals=True):
+    def clean_sessions(self, destroy_terminals=True, published_applications=False):
         """\
         Find X2Go terminals that have previously been started by the
         connected user on the remote X2Go server and terminate them.
 
         """
         session_list = self.list_sessions()
-        for session_name in session_list.keys():
+        if published_applications:
+            session_names = session_list.keys()
+        else:
+            session_names = [ _sn for _sn in session_list.keys() if not session_list[_sn].is_published_applications_provider() ]
+        for session_name in session_names:
             self.terminate(session_name=session_name, destroy_terminals=destroy_terminals)
 
     def is_connected(self):
diff --git a/x2go/backends/info/_stdout.py b/x2go/backends/info/_stdout.py
index ae6046c..c316ec7 100644
--- a/x2go/backends/info/_stdout.py
+++ b/x2go/backends/info/_stdout.py
@@ -30,6 +30,7 @@ __NAME__ = 'x2goserversessioninfo-pylib'
 
 # modules
 import types
+import re
 
 
 class X2goServerSessionInfoSTDOUT(object):
@@ -83,6 +84,10 @@ class X2goServerSessionInfoSTDOUT(object):
             print x2go_output
             raise e
 
+    def is_published_applications_provider(self):
+
+        return re.match('.*_stRPUBLISHED_.*', self.name)
+
     def is_running(self):
 
         return self.status == 'R'
diff --git a/x2go/backends/terminal/_stdout.py b/x2go/backends/terminal/_stdout.py
index 5179bdc..aee28b0 100644
--- a/x2go/backends/terminal/_stdout.py
+++ b/x2go/backends/terminal/_stdout.py
@@ -77,6 +77,10 @@ def _rewrite_cmd(cmd, params=None):
     # place quot marks around cmd if not empty string
     if cmd:
         cmd = '"%s"' % cmd
+
+    if ((type(params) == X2goSessionParams) and params.published_applications and cmd == ''):
+        cmd = 'PUBLISHED'
+
     return cmd
 
 
@@ -108,24 +112,33 @@ class X2goSessionParams(object):
 
         """
         cmd = self.cmd
+        published = self.published_applications
 
-        if cmd == 'RDP':
-            self.session_type = 'R'
-        elif cmd.startswith('rdesktop'):
-            self.session_type = 'R'
-        elif cmd == 'XDMCP':
-            self.session_type = 'D'
-        elif cmd in defaults.X2GO_DESKTOPSESSIONS.keys():
-            self.session_type = 'D'
-        elif os.path.basename(cmd) in defaults.X2GO_DESKTOPSESSIONS.values():
-            self.session_type = 'D'
-        elif self.session_type not in ("S", "shared", "shadow"):
-            self.session_type = 'R'
+        if published and self.cmd in ('', 'PUBLISHED'):
+            self.session_type = 'P'
+            self.cmd = 'PUBLISHED'
+        else:
+            if cmd == 'RDP':
+                self.session_type = 'R'
+            elif cmd.startswith('rdesktop'):
+                self.session_type = 'R'
+            elif cmd == 'XDMCP':
+                self.session_type = 'D'
+            elif cmd in defaults.X2GO_DESKTOPSESSIONS.keys():
+                self.session_type = 'D'
+            elif os.path.basename(cmd) in defaults.X2GO_DESKTOPSESSIONS.values():
+                self.session_type = 'D'
+            elif self.session_type not in ("S", "shared", "shadow"):
+                self.session_type = 'R'
 
         if self.session_type in ("D", "desktop"):
             self.session_type = 'D'
         elif self.session_type in ("S", "shared", "shadow"):
             self.session_type = 'S'
+        elif self.session_type in ("R", "rootless"):
+            self.session_type = 'R'
+        elif self.session_type in ("P", "published", "published_applications"):
+            self.session_type = 'P'
 
     def update(self, properties_to_be_updated={}):
         """\
@@ -174,6 +187,7 @@ class X2goTerminalSessionSTDOUT(object):
                  cache_type="unix-kde", 
                  keyboard='', kblayout='null', kbtype='null/null',
                  session_type="application", snd_system='pulse', snd_port=4713, cmd=None,
+                 published_applications=False,
                  set_session_title=False, session_title="", applications=[],
                  rdp_server=None, rdp_options=None,
                  xdmcp_server=None,
@@ -280,6 +294,9 @@ class X2goTerminalSessionSTDOUT(object):
         self.params.cmd = str(cmd)
         self.params.depth = str(depth)
 
+        self.params.published_applications = published_applications
+        self.published_applications = published_applications
+
         self.params.rdp_server = str(rdp_server)
         self.params.rdp_options = str(rdp_options)
         self.params.xdmcp_server = str(xdmcp_server)
@@ -375,6 +392,13 @@ class X2goTerminalSessionSTDOUT(object):
         """
         return self.session_info.name
 
+    def get_session_cmd(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.params.cmd
+
     def start_sound(self):
         """\
         Initialize Paramiko/SSH reverse forwarding tunnel for X2Go sound.
@@ -870,6 +894,8 @@ class X2goTerminalSessionSTDOUT(object):
             return True
         elif 'XSHAD' in cmd:
             return True
+        elif 'PUBLISHED' in cmd and 'X2GO_PUBLISHED_APPLICATIONS' in self.control_session.get_server_features():
+            return True
         elif cmd and cmd.startswith('/'):
             # check if full path is correct _and_ if application is in server path
             test_cmd = 'test -x %s && which %s && echo OK' % (cmd, os.path.basename(cmd.split()[0]))
@@ -900,7 +926,7 @@ class X2goTerminalSessionSTDOUT(object):
         @rtype: tuple of str
 
         """
-        if not self.has_command(_rewrite_cmd(self.params.cmd)):
+        if not self.has_command(_rewrite_cmd(self.params.cmd, params=self.params)):
             if self.client_instance:
                 self.client_instance.HOOK_no_such_command(profile_name=self.profile_name, session_name=self.session_info.name, cmd=self.params.cmd)
             return False
@@ -947,6 +973,32 @@ class X2goTerminalSessionSTDOUT(object):
 
         return stdout.read(), stderr.read()
 
+    def is_published_applications_provider(self):
+        """\
+        Returns true if this session runs in published applications mode.
+
+        @return: Returns C{True} is this session is a provider session for published applications.
+        @rtype: C{bool}
+
+        """
+        if self.session_info and self.is_running():
+            return self.session_info.is_published_applications_provider()
+        return False
+
+    def exec_published_application(self, exec_name):
+        """\
+        Executed a published application.
+
+        @param exec_name: application to be executed
+        @type exec_name: C{str}
+        """
+        cmd_line = [ "export DISPLAY=:%s && " % str(self.session_info.display),
+                     "setsid %s" % exec_name, 
+                     "&> /dev/null & exit",
+                   ]
+        self.logger('executing published application %s for %s with command line: %s' % (exec_name, self.profile_name, cmd_line), loglevel=log.loglevel_NOTICE)
+        (stdin, stdout, stderr) = self.control_session._x2go_exec_command(cmd_line)
+
     def ok(self):
         """\
         Returns C{True} if this X2Go session is up and running, 
@@ -999,7 +1051,9 @@ class X2goTerminalSessionSTDOUT(object):
         that can be passed to the class constructor.
 
         """
-        if not self.has_command(_rewrite_cmd(self.params.cmd)):
+        self.params.rewrite_session_type()
+
+        if not self.has_command(_rewrite_cmd(self.params.cmd, params=self.params)):
             if self.client_instance:
                 self.client_instance.HOOK_no_such_command(profile_name=self.profile_name, session_name=self.session_info.name, cmd=self.params.cmd)
             return False
@@ -1069,9 +1123,13 @@ class X2goTerminalSessionSTDOUT(object):
         self.proxy_subprocess = self.proxy.start_proxy()
         self.active_threads.append(self.proxy)
 
-        self.find_session_window()
-        self.auto_session_window_title()
-        #self.raise_session_window()
+        if self.params.session_type in ('D', 'S'):
+            self.find_session_window()
+            self.auto_session_window_title()
+            #self.raise_session_window()
+
+        if self.params.published_applications:
+            self.control_session.get_published_applications()
 
         return self.ok()
 
@@ -1145,9 +1203,14 @@ class X2goTerminalSessionSTDOUT(object):
         # on a session resume the user name comes in as a user ID. We have to translate this...
         self.session_info.username = self.control_session.remote_username()
 
-        self.find_session_window()
-        self.auto_session_window_title()
-        #self.raise_session_window()
+        if self.params.session_type in ('D', 'S'):
+            self.find_session_window()
+            self.auto_session_window_title()
+            #self.raise_session_window()
+
+        if self.is_published_applications_provider():
+            self.control_session.get_published_applications()
+            self.published_applications = True
 
         return self.ok()
 
diff --git a/x2go/client.py b/x2go/client.py
index 4adfb01..4ff1e26 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -1991,6 +1991,55 @@ class X2goClient(object):
         return self.session_registry.associated_sessions_of_profile_name(profile_name, return_objects=return_objects, return_session_names=return_session_names)
     __client_associated_sessions_of_profile_name = client_associated_sessions_of_profile_name
 
+    def client_pubapp_sessions_of_profile_name(self, profile_name, return_objects=False, return_session_names=False):
+        """\
+        Retrieve X2Go sessions of profile name <profile_name> that provide published applications .
+
+        @param profile_name: profile name
+        @type profile_name: C{str}
+        @param return_objects: return as list of X2Go session objects
+        @type return_objects: C{bool}
+        @param return_session_names: return as list of session names
+        @type return_session_names: C{bool}
+        @return: list of application publishing sessions of profile name
+        @rtype: C{list}
+        """
+        return self.session_registry.pubapp_sessions_of_profile_name(profile_name, return_objects=return_objects, return_session_names=return_session_names)
+    __client_pubapp_sessions_of_profile_name = client_pubapp_sessions_of_profile_name
+
+
+    def client_running_sessions_of_profile_name(self, profile_name, return_objects=False, return_session_names=False):
+        """\
+        Retrieve running X2Go sessions of profile name <profile_name>.
+
+        @param profile_name: profile name
+        @type profile_name: C{str}
+        @param return_objects: return as list of X2Go session objects
+        @type return_objects: C{bool}
+        @param return_session_names: return as list of session names
+        @type return_session_names: C{bool}
+        @return: list of running sessions of profile name
+        @rtype: C{list}
+        """
+        return self.session_registry.running_sessions_of_profile_name(profile_name, return_objects=return_objects, return_session_names=return_session_names)
+    __client_running_sessions_of_profile_name = client_running_sessions_of_profile_name
+
+    def client_suspended_sessions_of_profile_name(self, profile_name, return_objects=False, return_session_names=False):
+        """\
+        Retrieve suspended X2Go sessions of profile name <profile_name>.
+
+        @param profile_name: profile name
+        @type profile_name: C{str}
+        @param return_objects: return as list of X2Go session objects
+        @type return_objects: C{bool}
+        @param return_session_names: return as list of session names
+        @type return_session_names: C{bool}
+        @return: list of suspended sessions of profile name
+        @rtype: C{list}
+        """
+        return self.session_registry.suspended_sessions_of_profile_name(profile_name, return_objects=return_objects, return_session_names=return_session_names)
+    __client_suspended_sessions_of_profile_name = client_suspended_sessions_of_profile_name
+
     ###
     ### Provide access to the X2Go server's sessions DB
     ### 
@@ -2131,7 +2180,7 @@ class X2goClient(object):
     ### CLIENT OPERATIONS ON SESSIONS (listing sessions, terminating non-associated sessions etc.)
     ###
 
-    def clean_sessions(self, session_uuid):
+    def clean_sessions(self, session_uuid, published_applications=None):
         """\
         Find running X2Go sessions that have previously been started by the
         connected user on the remote X2Go server and terminate them.
@@ -2147,7 +2196,10 @@ class X2goClient(object):
         """
         _destroy_terminals = not ( self.auto_update_sessionregistry == True)
         session = self.session_registry(session_uuid)
-        session.clean_sessions(destroy_terminals=_destroy_terminals)
+        profile_name = session.get_profile_name()
+        if published_applications is None:
+            published_applications = self.session_profiles.get_profile_config(profile_name)['published']
+        session.clean_sessions(destroy_terminals=_destroy_terminals, published_applications=published_applications)
     __clean_sessions = clean_sessions
 
     def list_sessions(self, session_uuid=None, 
diff --git a/x2go/defaults.py b/x2go/defaults.py
index 57e30a3..ce9190f 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
@@ -283,7 +283,7 @@ X2GO_SESSIONPROFILE_DEFAULTS = {
     'sound': False, 'soundsystem': 'pulse', 'startsoundsystem': False, 'soundtunnel':True, 'defsndport':True, 'sndport':4713,
     'name': 'NEW_PROFILE', 'icon': ':icons/128x128/x2gosession.png',
     'host': '', 'user': CURRENT_LOCAL_USER, 'key': '', 'sshport': 22, 'krblogin': False,
-    'rootless': True, 'applications': X2GO_GENERIC_APPLICATIONS, 'command':'TERMINAL',
+    'rootless': True, 'applications': X2GO_GENERIC_APPLICATIONS, 'command':'TERMINAL', 'published': False,
     'rdpoptions': '-u X2GO_USER -p X2GO_PASSWORD', 'rdpserver': '',
     'print': False,
     'xdmcpserver': 'localhost',
@@ -406,3 +406,4 @@ X2GO_MIMEBOX_EXTENSIONS_BLACKLIST = [
 # X2Go desktop sharing
 X2GO_SHARE_VIEWONLY=0
 X2GO_SHARE_FULLACCESS=1
+
diff --git a/x2go/registry.py b/x2go/registry.py
index 4fe08a0..0d06a03 100644
--- a/x2go/registry.py
+++ b/x2go/registry.py
@@ -283,6 +283,11 @@ class X2goSessionRegistry(object):
                             self.master_sessions[_profile_name] = self(_session_uuid)
                             self(_session_uuid).set_master_session()
 
+                        elif self(_session_uuid).published_applications:
+                            self(self.master_sessions[_profile_name]()).unset_master_session()
+                            self.master_sessions[_profile_name] = self(_session_uuid)
+                            self(_session_uuid).set_master_session()
+
                         if _last_status['suspended']:
                             # from a suspended state
                             self.client_instance.HOOK_on_session_has_resumed_by_me(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
@@ -327,9 +332,13 @@ class X2goSessionRegistry(object):
                 if len(self.virgin_sessions_of_profile_name(profile_name)) > 1:
                     self.forget(_session_uuid)
 
-        for _profile_name in self.connected_profiles(return_profile_names=True):
+        for _profile_name in [ p for p in self.connected_profiles(return_profile_names=True) if p not in self.master_sessions.keys() ]:
             _running_sessions = self.running_sessions_of_profile_name(_profile_name)
-            if _profile_name not in self.master_sessions.keys() and _running_sessions:
+            _pubapp_sessions = [ _s for _s in self.pubapp_sessions_of_profile_name(_profile_name) if _s in _running_sessions ]
+            if _pubapp_sessions:
+                self.master_sessions[_profile_name] = _pubapp_sessions[0]
+                _pubapp_sessions[0].set_master_session()
+            elif _running_sessions:
                 self.master_sessions[_profile_name] = _running_sessions[0]
                 _running_sessions[0].set_master_session()
 
@@ -805,6 +814,28 @@ class X2goSessionRegistry(object):
         else:
             return self.associated_sessions() and [ s.get_uuid() for s in self.associated_sessions() if s.profile_name == profile_name ]
 
+    def pubapp_sessions_of_profile_name(self, profile_name, return_objects=True, return_session_names=False):
+        """\
+        For a given session profile name retrieve a list of sessions that can be providers for published application list.
+        If none of the C{return_*} options is specified a list of session UUID hashes will be returned.
+
+        @param profile_name: session profile name
+        @type profile_name: C{str}
+        @param return_objects: return as list of L{X2goSession} instances
+        @type return_objects: C{bool}
+        @param return_session_names: return as list of X2Go session names
+        @type return_session_names: C{bool}
+        @return: a session list (as UUID hashes, objects or session names)
+        @rtype: C{list}
+
+        """
+        if return_objects:
+            return self.associated_sessions() and [ s for s in self.associated_sessions() if s.published_applications ]
+        elif return_session_names:
+            return self.associated_sessions() and [ s.session_name for s in self.associated_sessions() if s.published_applications ]
+        else:
+            return self.associated_sessions() and [ s.get_uuid() for s in self.associated_sessions() if s.published_applications ]
+
     def registered_sessions_of_profile_name(self, profile_name, return_objects=True, return_session_names=False):
         """\
         For a given session profile name retrieve a list of sessions that are currently registered with this L{X2goClient} instance.
diff --git a/x2go/session.py b/x2go/session.py
index 4fe945c..fa83111 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -34,6 +34,7 @@ import types
 import uuid
 import time
 import gevent
+import re
 
 # Python X2Go modules
 import log
@@ -66,7 +67,7 @@ _X2GO_SESSION_PARAMS = ('geometry', 'depth', 'link', 'pack',
                         'rootdir', 'loglevel', 'profile_name', 'profile_id',
                         'print_action', 'print_action_args',
                         'convert_encoding', 'client_encoding', 'server_encoding',
-                        'proxy_options', 
+                        'proxy_options', 'published_applications',
                         'logger',
                         'control_backend', 'terminal_backend', 'proxy_backend',
                         'profiles_backend', 'settings_backend', 'printing_backend',
@@ -230,6 +231,21 @@ class X2goSession(object):
         self.ssh_rootdir = ssh_rootdir
         self.control_session = control_session
 
+        if params.has_key('published_applications'):
+            self.published_applications = params['published_applications']
+            if self.published_applications:
+                params['cmd'] = 'PUBLISHED'
+        else:
+            self.published_applications = params['published_applications'] = False
+
+        if params.has_key('cmd') and params['cmd'] != 'PUBLISHED':
+            self.published_applications = params['published_applications'] = False
+        self.published_applications_menu = None
+
+        if self.session_name:
+            if not re.match('.*_stRPUBLISHED_.*',self.session_name):
+                self.published_applications = params['published_applications'] = False
+
         self.control_params = {}
         self.terminal_params = {}
         self.sshproxy_params = {}
@@ -279,6 +295,10 @@ class X2goSession(object):
         self.init_control_session()
         self.terminal_session = None
 
+        if self.is_connected():
+            self.retrieve_server_features()
+
+
     def HOOK_session_startup_failed(self):
         """\
         HOOK method: called if the startup of a session failed.
@@ -683,6 +703,8 @@ class X2goSession(object):
         @rtype: C{str}
 
         """
+        if self.has_terminal_session():
+            return self.terminal_session.get_session_cmd()
         if self.terminal_params.has_key('cmd'):
             return self.terminal_params['cmd']
         return None
@@ -954,6 +976,18 @@ class X2goSession(object):
         """
         return self.server_features
 
+    def has_server_feature(self, feature):
+        """\
+        Check if C{feature} is a present feature of the connected X2Go server.
+
+        @param feature: an X2Go server feature as found in C{$SHAREDIR/x2go/feature.d/*}
+        @type feature: C{str}
+        @return: C{True} if the feature is presend
+        @rtype: C{bool}
+
+        """
+        return feature in self.get_server_features()
+
     def set_session_window_title(self, title=''):
         """\
         Modify session window title. If the session ID does not occur in the
@@ -1011,7 +1045,7 @@ class X2goSession(object):
         return self.connected
     __is_alive = is_alive
 
-    def clean_sessions(self, destroy_terminals=True):
+    def clean_sessions(self, destroy_terminals=True, published_applications=False):
         """\
         Clean all running sessions for the authenticated user on the remote X2Go server.
 
@@ -1024,7 +1058,7 @@ class X2goSession(object):
             except x2go_exceptions.X2goSessionException:
                 pass
 
-            self.control_session.clean_sessions(destroy_terminals=destroy_terminals)
+            self.control_session.clean_sessions(destroy_terminals=destroy_terminals, published_applications=published_applications)
         else:
             self._X2goSession__disconnect()
     __clean_sessions = clean_sessions
@@ -1138,14 +1172,13 @@ class X2goSession(object):
                     self.terminated = not (self.running or self.suspended)
                 else:
                     self.terminated = None
-            except KeyError:
+            except KeyError, e:
                 self.running = False
                 self.suspended = False
                 if not self.virgin:
                     self.terminated = True
             self.faulty = not (self.running or self.suspended or self.terminated or self.virgin)
 
-
         self._current_status = {
             'timestamp': time.time(),
             'server': self.server,
@@ -1161,9 +1194,46 @@ class X2goSession(object):
             raise e
 
         return True
-
     __update_status = update_status
 
+    def is_published_applications_provider(self):
+        """\
+        Returns true if this session runs in published applications mode.
+
+        @return: Returns C{True} is this session is a provider session for published applications.
+        @rtype: C{bool}
+
+        """
+        if self.is_running() and self.has_terminal_session():
+            return self.terminal_session.is_published_applications_provider()
+        return False
+
+    def get_published_applications(self):
+        """\
+        Return a list of published menu items from the X2Go server
+        for session type published applications.
+
+        @return: A C{list} of C{dict} elements. Each C{dict} elements has a 
+            C{desktop} key containing the text output of a .desktop file and
+            an C{icon} key which contains the desktop icon data base64 encoded 
+        @rtype: C{list}
+
+        """
+        return self.control_session.get_published_applications()
+
+    def exec_published_application(self, exec_name):
+        """\
+        Execute an application while in published application mode.
+
+        @param exec_name: command to execute on server
+        @type exec_name: C{str}
+
+        """
+        if self.terminal_session is not None:
+            self.logger('for %s executing published application: %s' % (self.profile_name, exec_name), loglevel=log.loglevel_NOTICE)
+            self.terminal_session.exec_published_application(exec_name)
+    __exec_published_application = exec_published_application
+
     def resume(self, session_name=None):
         """\
         Resume or continue a suspended / running X2Go session on the
@@ -1189,7 +1259,14 @@ class X2goSession(object):
             # sockets, thus  we plainly have to wait a while
             if self.is_running():
                 self.suspend()
-                gevent.sleep(10)
+                gevent.sleep(5)
+
+            try:
+                if self.published_applications:
+                    self.published_applications_menu = self.get_published_applications()
+            except:
+                # FIXME: test the code to see what exceptions may occur here...
+                raise
 
             self.terminal_session = _control.resume(session_name=self.session_name,
                                                     session_instance=self,
@@ -1209,6 +1286,9 @@ class X2goSession(object):
                 if _new_session:
                     self.terminal_session.run_command(env=self.session_environment)
 
+                if self.get_session_cmd() != 'PUBLISHED':
+                    self.published_applications = False
+
                 if self._SUPPORTED_SOUND and self.terminal_session.params.snd_system is not 'none':
                     self.terminal_session and not self.faulty and self.terminal_session.start_sound()
                 else:
diff --git a/x2go/utils.py b/x2go/utils.py
index 8bec574..1b23cdc 100644
--- a/x2go/utils.py
+++ b/x2go/utils.py
@@ -166,6 +166,7 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
             'sshproxytunnel': 'sshproxy_tunnel',
             'sessiontitle': 'session_title',
             'setsessiontitle': 'set_session_title',
+            'published': 'published_applications',
     }
     _speed_dict = {
             '0': 'modem',
@@ -505,9 +506,12 @@ def set_session_window_title(session_window, session_title):
 
     """
     if _X2GOCLIENT_OS != 'Windows':
-        session_window.set_wm_name(str(session_title))
-        session_window.set_wm_icon_name(str(session_title))
-        _X_DISPLAY.sync()
+        try:
+            session_window.set_wm_name(str(session_title))
+            session_window.set_wm_icon_name(str(session_title))
+            _X_DISPLAY.sync()
+        except Xlib.error.BadWindow:
+            pass
 
 def raise_session_window(session_window):
     """\


hooks/post-receive
-- 
python-x2go.git (Python X2Go Client API)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-x2go.git" (Python X2Go Client API).




More information about the x2go-commits mailing list