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

X2Go dev team git-admin at x2go.org
Mon Mar 12 01:22:36 CET 2012


The branch, master has been updated
       via  0eff893ffaa6c3358e4ca2184bebe5b471d529f0 (commit)
       via  f2e8361dc164f7ae5215745fe7d56ac9cf25fca0 (commit)
       via  3dc28f3224ab59dcccb67635b679d726ac0ec00b (commit)
       via  2a96e1e2fb82f305f3d2d5c88f0ece5eb7624ba1 (commit)
       via  8d90554cf0190a23569d52c31aee3c8811d1bcc2 (commit)
       via  ec470470fb63f0451023d613943f3fbc86daeb63 (commit)
      from  b9421ed58590787180ae7069108d926a314bbda7 (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 -----------------------------------------------------------------
commit 0eff893ffaa6c3358e4ca2184bebe5b471d529f0
Author: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
Date:   Sat Mar 10 15:31:30 2012 +0100

    Add published applications support.

commit f2e8361dc164f7ae5215745fe7d56ac9cf25fca0
Author: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
Date:   Sat Mar 10 15:03:58 2012 +0100

    fix x2gofeaturelist query

commit 3dc28f3224ab59dcccb67635b679d726ac0ec00b
Author: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
Date:   Sat Mar 10 13:41:27 2012 +0100

    silence which command

commit 2a96e1e2fb82f305f3d2d5c88f0ece5eb7624ba1
Author: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
Date:   Sat Mar 10 13:38:24 2012 +0100

    Retrieve feature list from X2Go server per session.

commit 8d90554cf0190a23569d52c31aee3c8811d1bcc2
Author: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
Date:   Sat Mar 10 12:47:13 2012 +0100

    Update list of unsupported session options.

commit ec470470fb63f0451023d613943f3fbc86daeb63
Author: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
Date:   Sat Mar 10 12:29:31 2012 +0100

    Amend list of default session options.

-----------------------------------------------------------------------

Summary of changes:
 debian/changelog                  |    4 +
 x2go/backends/control/_stdout.py  |   60 +++++++++++++++++++-
 x2go/backends/info/_stdout.py     |    5 ++
 x2go/backends/terminal/_stdout.py |  104 +++++++++++++++++++++++++++-------
 x2go/client.py                    |   56 ++++++++++++++++++-
 x2go/defaults.py                  |   15 +++--
 x2go/registry.py                  |   35 +++++++++++-
 x2go/session.py                   |  113 ++++++++++++++++++++++++++++++++++--
 x2go/utils.py                     |   15 ++++-
 9 files changed, 363 insertions(+), 44 deletions(-)

The diff of changes is:
diff --git a/debian/changelog b/debian/changelog
index a9e01f8..8097dc9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -36,6 +36,10 @@ python-x2go (0.1.2.0-0~x2go1) UNRELEASED; urgency=low
       mimeboxactions.py.
     - Run print actions in background (gevent.spawn).
     - Run MIME box actions in background (gevent.spawn).
+    - 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 9d59807..6b3dd1f 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -122,6 +122,8 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         self._remote_home = None
         self._remote_group = {}
 
+        self._server_features = None
+
         self.locked = False
 
         if logger is None:
@@ -139,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())
@@ -239,6 +243,21 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             raise x2go_exceptions.X2goControlSessionException('the X2Go control session is not connected')
         return _retval
 
+
+    @property
+    def _x2go_server_features(self):
+        if self._server_features is None:
+            (stdin, stdout, stderr) = self._x2go_exec_command('which x2gofeaturelist >/dev/null && x2gofeaturelist')
+            self._server_features = stdout.read().split('\n')
+            self.logger('server-side X2Go features are: %s' % self._server_features, loglevel=log.loglevel_DEBUG)
+            return self._server_features
+        else:
+            return self._server_features
+
+    def query_server_features(self):
+        return self._x2go_server_features
+    get_server_features = query_server_features
+
     @property
     def _x2go_remote_home(self):
 
@@ -574,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. 
@@ -809,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 f64663d..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, 
@@ -987,6 +1039,7 @@ class X2goTerminalSessionSTDOUT(object):
 
         @return: X2Go session connected?
         @rtype: bool
+
         """
         return self.control_session.is_connected()
 
@@ -998,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
@@ -1068,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()
 
@@ -1144,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 7edb59e..ce9190f 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
@@ -271,19 +271,19 @@ X2GO_GENERIC_APPLICATIONS = [ 'WWWBROWSER', 'MAILCLIENT', 'OFFICE', 'TERMINAL',
 """X2go's generic applications."""
 
 X2GO_SESSIONPROFILE_DEFAULTS = {
-    'autostart': False, 'setsessiontitle': False, 'sessiontitle': "",
+    'autologin': False, 'autostart': False, 'setsessiontitle': False, 'sessiontitle': "",
     'speed': 2, 'pack': '16m-jpeg', 'quality': 9,
     'iconvto': 'UTF-8', 'iconvfrom': 'UTF-8', 'useiconv': False,
     'usesshproxy': False, 'sshproxyhost': '', 'sshproxyuser': '', 'sshproxytunnel': '', 'sshproxykeyfile': '',
     'useexports': True, 'fstunnel': True, 'export': '',
     'usemimebox': False, 'mimeboxextensions': '', 'mimeboxaction': 'OPEN',
     'fullscreen': False,
-    'width': 800,'height': 600,'dpi': 96,'setdpi': False, 'xinerama': False, 
-    'usekbd':True, 'layout': 'us', 'type': 'pc105/us',
-    '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,
-    'rootless': True, 'applications': X2GO_GENERIC_APPLICATIONS, 'command':'TERMINAL',
+    'width': 800,'height': 600,'dpi': 96,'setdpi': False, 'xinerama': False, 'multidisp': False,
+    'usekbd': True, 'layout': 'us', 'type': 'pc105/us',
+    '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', '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 1d5c062..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 = {}
@@ -237,6 +253,7 @@ class X2goSession(object):
         self.shared_folders = []
 
         self.session_environment = {}
+        self.server_features = []
 
         try: del self.control_params['server']
         except: pass
@@ -278,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.
@@ -682,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
@@ -909,6 +932,7 @@ class X2goSession(object):
 
         if self.connected:
             self.update_status()
+            self.retrieve_server_features()
 
         return self.connected
     __connect = connect
@@ -935,6 +959,35 @@ class X2goSession(object):
         return retval
     __disconnect = disconnect
 
+    def retrieve_server_features(self):
+        """\
+        Query the X2Go server for a list of supported features.
+
+        """
+        self.server_features = self.control_session.query_server_features()
+
+    def get_server_features(self):
+        """\
+        Return a list of X2Go server-sides features (supported functionalities).
+
+        @return: a C{list} of X2Go feature names.
+        @rtype: C{list}
+
+        """
+        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
@@ -992,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.
 
@@ -1005,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
@@ -1119,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,
@@ -1142,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
@@ -1170,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,
@@ -1190,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 15a544d..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',
@@ -252,14 +253,17 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
 
     # currently known but ignored in Python X2go
     _ignored_options = [
+            'autostart',
+            'autologin',
             'dpi',
             'setdpi',
             'startsoundsystem',
             'soundtunnel',
             'defsndport',
             'icon',
-            'autostart',
             'xinerama',
+            'multidisp',
+            'krblogin',
     ]
     for i in _ignored_options:
         del _params[i]
@@ -502,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