[X2Go-Commits] python-x2go.git - release/0.4.0.x (branch) updated: c4b70151df3b4f2572f1d9dc1699f29b072016b7

X2Go dev team git-admin at x2go.org
Tue Jan 7 16:16:07 CET 2014


The branch, release/0.4.0.x has been updated
       via  c4b70151df3b4f2572f1d9dc1699f29b072016b7 (commit)
      from  f630352d855595d4aae0c03842ef7a5bd418209d (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:
 x2go/backends/control/_stdout.py  |   97 ++++++++---
 x2go/backends/info/_stdout.py     |   13 ++
 x2go/backends/profiles/_file.py   |   14 +-
 x2go/backends/terminal/_stdout.py |   35 ++--
 x2go/cache.py                     |   41 ++---
 x2go/client.py                    |  292 ++++++++++++++++++++++-----------
 x2go/defaults.py                  |   13 +-
 x2go/guardian.py                  |   35 ++--
 x2go/inifiles.py                  |    2 +-
 x2go/registry.py                  |  323 ++++++++++++++++++++++++++++++-------
 x2go/session.py                   |  270 +++++++++++++++++++++++++++----
 x2go/utils.py                     |   12 +-
 x2go/x2go_exceptions.py           |    2 +
 13 files changed, 880 insertions(+), 269 deletions(-)

The diff of changes is:
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index 3377ff6..4e67d88 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -50,8 +50,12 @@ def _rerewrite_blanks(cmd):
         cmd = cmd.replace("X2GO_SPACE_CHAR", " ")
     return cmd
 
-def _rewrite_password(cmd, password):
+def _rewrite_password(cmd, user=None, password=None):
 
+    # if there is a ,,-u X2GO_USER'' parameter in RDP options then we will replace 
+    # it by our X2go session password
+    if cmd and user:
+        cmd = cmd.replace('X2GO_USER', user)
     # if there is a ,,-p X2GO_PASSWORD'' parameter in RDP options then we will replace 
     # it by our X2go session password
     if cmd and password:
@@ -94,11 +98,15 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         self.terminated_terminals = []
 
         self.profile_name = profile_name
+        self.hostname = None
+        self.port = None
 
         self._session_auth_rsakey = None
         self._remote_home = None
         self._remote_group = {}
 
+        self.locked = False
+
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
         else:
@@ -140,6 +148,12 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
     def _x2go_exec_command(self, cmd_line, loglevel=log.loglevel_INFO, **kwargs):
 
+        while self.locked:
+            gevent.sleep(.1)
+
+        self.locked = True
+        _retval = None
+
         if type(cmd_line) == types.ListType:
             cmd = " ".join(cmd_line)
         else:
@@ -150,7 +164,8 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             timeout.start()
             try:
                 self.logger('executing command on X2go server: %s' % _rerewrite_blanks(cmd), loglevel)
-                return self.exec_command(_rewrite_password(cmd, self._session_password), **kwargs)
+                _retval = self.exec_command(_rewrite_password(cmd, user=self.get_transport().get_username(), password=self._session_password), **kwargs)
+                self.locked = False
             except AttributeError:
                 raise x2go_exceptions.X2goControlSessionException('the X2go control session has died unexpectedly')
             except EOFError:
@@ -158,11 +173,13 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             except gevent.timeout.Timeout:
                 raise x2go_exceptions.X2goControlSessionException('the X2go control session command timed out')
             finally:
+                self.locked = False
                 timeout.cancel()
 
         else:
+            self.locked = False
             raise x2go_exceptions.X2goControlSessionException('the X2go control session is not connected')
-        return None
+        return _retval
 
     @property
     def _x2go_remote_home(self):
@@ -293,6 +310,9 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         else:
             raise paramiko.AuthenticationException()
 
+        self.hostname = hostname
+        self.port = port
+
         # if we succeed, we immediately grab us an sFTP client session
         self.sftp_client = self.open_sftp()
 
@@ -306,12 +326,23 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
         return (self.get_transport() is not None)
 
+    def dissociate(self, terminal_session):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        for t_name in self.associated_terminals.keys():
+            if self.associated_terminals[t_name] == terminal_session:
+                del self.associated_terminals[t_name]
+                if self.terminated_terminals.has_key(t_name):
+                    del self.terminated_terminals[t_name]
+
     def disconnect(self):
         """\
         STILL UNDOCUMENTED
 
         """
-        if self.associated_terminals is not None:
+        if self.associated_terminals:
             t_names = self.associated_terminals.keys()
             for  t_obj in self.associated_terminals.values():
                 try:
@@ -320,9 +351,12 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
                     pass
                 except x2go_exceptions.X2goControlSessionException:
                     pass
-                del t_obj
+                t_obj.__del__()
             for t_name in t_names:
-                del self.associated_terminals[t_name]
+                try:
+                    del self.associated_terminals[t_name]
+                except KeyError:
+                    pass
 
         self._remote_home = None
         self._remote_group = {}
@@ -426,10 +460,28 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
         else:
 
-            (stdin, stdout, stderr) = self._x2go_exec_command("x2golistsessions")
+            # this _success loop will catch errors in case the x2golistsessions output is corrupt
+            # this should not be needed and is a workaround for the current X2go server implementation
+            _success = False
+            while not _success:
 
-            _stdout_read = stdout.read()
-            _listsessions = self._list_backend(_stdout_read, info_backend=self._info_backend).sessions
+                (stdin, stdout, stderr) = self._x2go_exec_command("x2golistsessions")
+
+                _stdout_read = stdout.read()
+
+                try:
+                    _listsessions = self._list_backend(_stdout_read, info_backend=self._info_backend).sessions
+                    _success = True
+                except:
+                    gevent.sleep(1)
+
+            # update internal variables when list_sessions() is called
+            for _session_name, _session_info in self.associated_terminals.items():
+                if _session_name not in _listsessions.keys():
+                    del self.associated_terminals[_session_name]
+                    self.terminated_terminals.append(_session_name)
+                elif _session_info.is_suspended():
+                    del self.associated_terminals[_session_name]
 
             return _listsessions
 
@@ -439,9 +491,9 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         connected user on the remote X2go server and terminate them.
 
         """
-        session_infos = self.list_sessions()
-        for session_info in session_infos.values():
-            self.terminate(session_name=session_info)
+        session_list = self.list_sessions()
+        for session_name in session_list.keys():
+            self.terminate(session_name=session_name)
 
     def is_connected(self):
         """\
@@ -469,7 +521,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         session_infos = self.list_sessions()
         if session_name in session_infos.keys():
             return session_infos[session_name].is_running()
-        return False
+        return None
 
     def is_suspended(self, session_name):
         """\
@@ -483,7 +535,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         session_infos = self.list_sessions()
         if session_name in session_infos.keys():
             return session_infos[session_name].is_suspended()
-        return False
+        return None
 
     def has_terminated(self, session_name):
         """\
@@ -533,8 +585,10 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             (stdin, stdout, stderr) = self._x2go_exec_command("x2gosuspend-session %s" % session_name, loglevel=log.loglevel_DEBUG)
             dummy_stdout = stdout.read()
             dummy_stderr = stderr.read()
-            self.associated_terminals[session_name].__del__()
-            del self.associated_terminals[session_name]
+            if self.associated_terminals.has_key(session_name):
+                if self.associated_terminals[session_name] is not None:
+                    self.associated_terminals[session_name].__del__()
+                del self.associated_terminals[session_name]
             _ret = True
 
         else:
@@ -567,19 +621,20 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         _session_names = [ t.get_session_name() for t in self.associated_terminals.values() ]
         if session_name in _session_names:
 
-            self.logger('suspending associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
+            self.logger('terminating associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
             (stdin, stdout, stderr) = self._x2go_exec_command("x2goterminate-session %s" % session_name, loglevel=log.loglevel_DEBUG)
             dummy_stdout = stdout.read()
             dummy_stderr = stderr.read()
-            if self.associated_terminals[session_name] is not None:
-                self.associated_terminals[session_name].__del__()
-            del self.associated_terminals[session_name]
+            if self.associated_terminals.has_key(session_name):
+                if self.associated_terminals[session_name] is not None:
+                    self.associated_terminals[session_name].__del__()
+                del self.associated_terminals[session_name]
             self.terminated_terminals.append(session_name)
             _ret = True
 
         else:
 
-            self.logger('suspending non-associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
+            self.logger('terminating non-associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
             (stdin, stdout, stderr) = self._x2go_exec_command("x2goterminate-session %s" % session_name, loglevel=log.loglevel_DEBUG)
             dummy_stdout = stdout.read()
             dummy_stderr = stderr.read()
diff --git a/x2go/backends/info/_stdout.py b/x2go/backends/info/_stdout.py
index a35f9b0..9abbdd1 100644
--- a/x2go/backends/info/_stdout.py
+++ b/x2go/backends/info/_stdout.py
@@ -66,11 +66,13 @@ class X2goServerSessionInfoSTDOUT(object):
             print 'Encountered IndexError: %s' % str(e)
             print 'THIS SHOULD NOT HAPPEN... HERE IS THE x2golistsessions OUTPUT THAT CAUSED THE ERROR...'
             print x2go_output
+            raise e
         except ValueError, e:
             # DEBUGGING CODE
             print 'Encountered IndexError: %s' % str(e)
             print 'THIS SHOULD NOT HAPPEN... HERE IS THE x2golistsessions OUTPUT THAT CAUSED THE ERROR...'
             print x2go_output
+            raise e
 
     def is_running(self):
 
@@ -173,4 +175,15 @@ class X2goServerSessionListSTDOUT(object):
             s_info._parse_x2golistsessions_line(line)
             self.sessions[s_info.name] = s_info
 
+    def __call__(self):
+        return self.sessions
 
+    def get_session_info(self, session_name):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        try:
+            return self.sessions[session_name]
+        except KeyError:
+            return None
diff --git a/x2go/backends/profiles/_file.py b/x2go/backends/profiles/_file.py
index c9a1888..0c109af 100644
--- a/x2go/backends/profiles/_file.py
+++ b/x2go/backends/profiles/_file.py
@@ -125,6 +125,13 @@ class X2goSessionProfilesFILE(inifiles.X2goIniFile):
             _profile_config[option] = self.get(_profile_id, option, key_type=self.get_profile_option_type(option))
         return _profile_config
 
+    def default_profile_config(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return copy.deepcopy(self.defaultSessionProfile)
+
     def has_profile(self, profile_id_or_name):
         try:
             _profile_id = self.check_profile_id_or_name(profile_id_or_name)
@@ -201,14 +208,15 @@ class X2goSessionProfilesFILE(inifiles.X2goIniFile):
 
         return profile_id
 
-    def delete_profile(self, profile_id):
+    def delete_profile(self, profile_id_or_name):
         """\
         STILL UNDOCUMENTED
 
         """
-        self.iniConfig.remove_section(profile_id)
+        _profile_id = self.check_profile_id_or_name(profile_id_or_name)
+        self.iniConfig.remove_section(_profile_id)
         self.write_user_config = True
-        self.writeIniFile()
+        self.write()
 
     def check_profile_id_or_name(self, profile_id_or_name):
         """\
diff --git a/x2go/backends/terminal/_stdout.py b/x2go/backends/terminal/_stdout.py
index 91821d2..ce2e9e3 100644
--- a/x2go/backends/terminal/_stdout.py
+++ b/x2go/backends/terminal/_stdout.py
@@ -299,13 +299,16 @@ class X2goTerminalSessionSTDOUT(object):
     def _x2go_tidy_up(self):
 
         if self.proxy is not None:
-            self.proxy.__del__()
+            self.release_proxy()
 
         try:
             if self.control_session.get_transport() is not None:
-                for _tunnel in [ _tun[1] for _tun in self.reverse_tunnels[self.session_info.name].values() ]:
-                    if _tunnel is not None:
-                        _tunnel.__del__()
+                try:
+                    for _tunnel in [ _tun[1] for _tun in self.reverse_tunnels[self.session_info.name].values() ]:
+                        if _tunnel is not None:
+                            _tunnel.__del__()
+                except KeyError:
+                    pass
 
             if self.print_queue is not None:
                 self.print_queue.__del__()
@@ -737,11 +740,8 @@ class X2goTerminalSessionSTDOUT(object):
         @rtype: bool
 
         """
-        self.logger('suspending terminal session: %s' % self.session_info, log.loglevel_DEBUG)
-        (stdin, stdout, stderr) = self.control_session._x2go_exec_command("x2gosuspend-session %s" % self.session_info, loglevel=log.loglevel_DEBUG)
-        dummy_stdout = stdout.read()
-        dummy_stderr = stderr.read()
-        self.proxy.__del__()
+        self.control_session.suspend(session_name=self.session_info.name)
+        self.release_proxy()
 
         # TODO: check if session has really suspended
         _ret = True
@@ -756,13 +756,20 @@ class X2goTerminalSessionSTDOUT(object):
         @rtype: bool
 
         """
-        self.logger('terminating terminal session: %s' % self.session_info, log.loglevel_INFO)
-        (stdin, stdout, stderr) = self.control_session._x2go_exec_command("x2goterminate-session %s" % self.session_info, loglevel=log.loglevel_DEBUG)
-        dummy_stdout = stdout.read()
-        dummy_stderr = stderr.read()
-        self.proxy.__del__()
+        self.control_session.terminate(session_name=self.session_info.name)
+        self.release_proxy()
 
         # TODO: check if session has really suspended
         _ret = True
 
         return _ret
+
+    def release_proxy(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        try:
+            self.proxy.__del__()
+        except:
+            pass
diff --git a/x2go/cache.py b/x2go/cache.py
index 2dc78cc..e0b4dfd 100644
--- a/x2go/cache.py
+++ b/x2go/cache.py
@@ -38,12 +38,10 @@ class X2goListSessionsCache(object):
     """
     x2go_listsessions_cache = {}
 
-    def __init__(self, client, refresh_interval=5, logger=None, loglevel=log.loglevel_DEFAULT):
+    def __init__(self, client_instance, logger=None, loglevel=log.loglevel_DEFAULT):
         """\
         @param client: the L{X2goClient} instance that uses this L{X2goListSessionsCache}
         @type client: C{instance}
-        @param refresh_interval: refresh interval of the list sessions cache in seconds
-        @type refresh_interval: C{int}
         @param logger: you can pass an L{X2goLogger} object to the L{X2goListSessionsCache} constructor
         @type logger: C{instance}
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
@@ -60,49 +58,34 @@ class X2goListSessionsCache(object):
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
-        self.client = client
-        self.refresh_interval = refresh_interval
+        self.client_instance = client_instance
 
-    def check_cache(self, seconds=None):
-
-        if seconds and (seconds % self.refresh_interval != 0):
-            return
+    def check_cache(self):
 
         for profile_name in self.x2go_listsessions_cache.keys():
-            if profile_name not in self.client.connected_profiles(return_profile_names=True):
+            if profile_name not in self.client_instance.connected_profiles(return_profile_names=True):
                 del self.x2go_listsessions_cache[profile_name]
 
-    def update_all(self, seconds=None):
+    def update_all(self):
         """\
         Update L{X2goListSessionsCache} for all connected profiles.
 
-        @param seconds: time since control session is up
-        @type seconds: C{int}
-
         """
-        if seconds and (seconds % self.refresh_interval != 0):
-            return
+        for profile_name in self.client_instance.connected_profiles(return_profile_names=True):
+            self.update(profile_name)
 
-        for profile_name in self.client.connected_profiles(return_profile_names=True):
-            self.update(profile_name, seconds=seconds)
+        self.check_cache()
 
-        self.check_cache(seconds=seconds)
-
-    def update(self, profile_name, seconds=None):
+    def update(self, profile_name):
         """\
         Update the L{X2goListSessionsCache} for profile C{profile_name}.
 
         @param profile_name: name of profile to update
         @type profile_name: C{str}
-        @param seconds: time since control session is up
-        @type seconds: C{int}
 
         """
-        if seconds and (seconds % self.refresh_interval != 0):
-            return
-
         self.last_listsessions_cache = copy.deepcopy(self.x2go_listsessions_cache)
-        control_session = self.client.client_control_session_of_name(profile_name)
+        control_session = self.client_instance.client_control_session_of_profile_name(profile_name)
         try:
             self.x2go_listsessions_cache[profile_name] = control_session.list_sessions()
         except x2go_exceptions.X2goControlSessionException, e:
@@ -117,7 +100,7 @@ class X2goListSessionsCache(object):
         Retrieve the current cache content of L{X2goListSessionsCache}.
 
         """
-        profile_name = self.client.get_session_profile_name(session_uuid)
+        profile_name = self.client_instance.get_session_profile_name(session_uuid)
         if self.is_cached(session_uuid=session_uuid):
             return self.x2go_listsessions_cache[profile_name]
         else:
@@ -129,5 +112,5 @@ class X2goListSessionsCache(object):
 
         """
         if profile_name is None and session_uuid:
-            profile_name = self.client.get_session_profile_name(session_uuid)
+            profile_name = self.client_instance.get_session_profile_name(session_uuid)
         return self.x2go_listsessions_cache.has_key(profile_name)
diff --git a/x2go/client.py b/x2go/client.py
index bacd3ab..56c909f 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -174,7 +174,7 @@ class X2goClient(object):
     session object etc.) and connected to it (authentication). For these two steps
     use these methods: L{X2goClient.register_session()} and L{X2goClient.connect_session()}.
     """
-    def __init__(self, use_cache=True, start_xserver=False,
+    def __init__(self, 
                  control_backend=control.X2goControlSession,
                  terminal_backend=terminal.X2goTerminalSession,
                  info_backend=info.X2goServerSessionInfo,
@@ -186,6 +186,12 @@ class X2goClient(object):
                  client_rootdir=None,
                  sessions_rootdir=None,
                  ssh_rootdir=None,
+                 start_xserver=False,
+                 use_listsessions_cache=False, 
+                 auto_update_listsessions_cache=False,
+                 auto_update_sessionregistry=False,
+                 auto_register_sessions=False,
+                 refresh_interval=5,
                  logger=None, loglevel=log.loglevel_DEFAULT):
         """\
         @param logger: you can pass an L{X2goLogger} object to the
@@ -253,28 +259,40 @@ class X2goClient(object):
                 # presume the running XServer listens on :0
                 os.environ.update({'DISPLAY': 'localhost:0'})
 
-        self.session_registry = X2goSessionRegistry(logger=self.logger)
-        self.session_guardian = X2goSessionGuardian(self, enable_cache=use_cache, logger=self.logger)
-        if use_cache:
+        self.session_registry = X2goSessionRegistry(self, logger=self.logger)
+        self.session_guardian = X2goSessionGuardian(self, auto_update_listsessions_cache=auto_update_listsessions_cache & use_listsessions_cache, 
+                                                    auto_update_sessionregistry=auto_update_sessionregistry,
+                                                    auto_register_sessions=auto_register_sessions, 
+                                                    refresh_interval=refresh_interval,
+                                                    logger=self.logger
+                                                   )
+        if use_listsessions_cache:
             self.listsessions_cache = X2goListSessionsCache(self, logger=self.logger)
 
-        self.use_cache = use_cache
+        self.use_listsessions_cache = use_listsessions_cache
 
     # user hooks for detecting/notifying what happened during application runtime
     def HOOK_no_known_xserver_found(self):
         self.logger('the Python X2go module could not find any usable XServer application, you will not be able to start X2go sessions without XServer', loglevel=log.loglevel_WARN)
     def HOOK_open_print_dialog(self, filename, profile_name='UNKNOWN', session_name='UNKNOWN'):
-        self.logger('incoming print job,, %s'' detected by X2goClient hook method' % filename, loglevel=log.loglevel_WARN)
+        self.logger('HOOK_open_print_dialog: incoming print job,, %s'' detected by X2goClient hook method' % filename, loglevel=log.loglevel_WARN)
     def HOOK_on_control_session_death(self, profile_name):
-        self.logger('the control session of profile %s has died unexpectedly' % profile_name, loglevel=log.loglevel_WARN)
-    def HOOK_on_session_got_suspended_from_within(self, session_uuid):
-        self.logger('session %s has been suspended from within the application' % self.session_registry(session_uuid).get_session_name(), loglevel=log.loglevel_WARN)
-    def HOOK_on_session_got_terminated_from_within(self, session_uuid):
-        self.logger('session %s has been terminated from within the application' % self.session_registry(session_uuid).get_session_name(), loglevel=log.loglevel_WARN)
+        self.logger('HOOK_on_control_session_death: the control session of profile %s has died unexpectedly' % profile_name, loglevel=log.loglevel_WARN)
+
+    def HOOK_on_session_has_started_by_me(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+        self.logger('HOOK_on_session_has_started_by_me (session_uuid: %s, profile_name: %s): a new session %s has been started by this application' %  (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+    def HOOK_on_session_has_started_by_other(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+        self.logger('HOOK_on_session_has_started (session_uuid: %s, profile_name: %s): a new session %s has started been started by other application' %  (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+    def HOOK_on_session_has_resumed_by_me(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+        self.logger('HOOK_on_session_has_resumed_by_me (session_uuid: %s, profile_name: %s): suspended session %s has been resumed by this application' %  (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+    def HOOK_on_session_has_resumed_by_other(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+        self.logger('HOOK_on_session_has_resumed_by_other (session_uuid: %s, profile_name: %s): suspended session %s has been resumed by other application' %  (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+    def HOOK_on_session_has_been_suspended(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+        self.logger('HOOK_on_session_has_been_suspended (session_uuid: %s, profile_name: %s): session %s has been suspended' %  (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+    def HOOK_on_session_has_terminated(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+        self.logger('HOOK_on_session_has_terminated (session_uuid: %s, profile_name: %s): session %s has terminated' % (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
 
     def _detect_backend_classes(self):
-
-
         # CONTROL session backend
         if type(self.control_backend) is types.StringType:
             try:
@@ -413,7 +431,7 @@ class X2goClient(object):
             sessions[_obj.get_profile_name()] = _obj
         return sessions
 
-    def register_session(self, server=None, profile_id=None, profile_name=None, 
+    def register_session(self, server=None, profile_id=None, profile_name=None, session_name=None,
                          printing=False, share_local_folders=[], return_object=False, 
                          force=False, **kwargs):
         """\
@@ -479,20 +497,6 @@ class X2goClient(object):
 
             _profile_id = self.session_profiles.check_profile_id_or_name(_p)
             _profile_name = self.session_profiles.to_profile_name(_profile_id)
-
-            # detect if we are re-registering a session profile that is already been initialized
-            # by register_all_session_profiles
-            _profile_siblings = self.session_registry.registered_sessions_of_name(_profile_name)
-            if (not force) and (len(_profile_siblings) == 1) and not _profile_siblings[0].has_terminal_session():
-
-                session_uuid = _profile_siblings[0].get_uuid()
-                self.logger('using already initially-registered-by-profile session %s' % session_uuid, log.loglevel_NOTICE, tag=self._logger_tag)
-
-                if return_object:
-                    return self.session_registry(session_uuid)
-                else:
-                    return session_uuid
-
             _params = self.session_profiles.to_session_params(_profile_id)
             del _params['profile_name']
 
@@ -517,6 +521,7 @@ class X2goClient(object):
 
         session_uuid = self.session_registry.register(server=server,
                                                       profile_id=_profile_id, profile_name=_profile_name,
+                                                      session_name=session_name,
                                                       control_backend=self.control_backend,
                                                       terminal_backend=self.terminal_backend,
                                                       info_backend=self.info_backend,
@@ -527,6 +532,7 @@ class X2goClient(object):
                                                       client_rootdir=self.client_rootdir,
                                                       sessions_rootdir=self.sessions_rootdir,
                                                       ssh_rootdir=self.ssh_rootdir,
+                                                      keep_controlsession_alive=True,
                                                       **_params)
 
         self.logger('initializing X2go session...', log.loglevel_NOTICE, tag=self._logger_tag)
@@ -566,7 +572,7 @@ class X2goClient(object):
         return self.session_registry(session_uuid).get_username()
     __get_session_username = get_session_username
 
-    def get_session_server(self, session_uuid):
+    def get_session_server_peername(self, session_uuid):
         """\
         After a session has been set up you can query the 
         hostname of the host the session is connected to (or 
@@ -580,8 +586,8 @@ class X2goClient(object):
         @rtype: tuple
 
         """
-        return self.session_registry(session_uuid).get_server()
-    __get_session_server = get_session_server
+        return self.session_registry(session_uuid).get_server_peername()
+    __get_session_server_peername = get_session_server_peername
 
     def get_session(self, session_uuid):
         """\
@@ -653,8 +659,8 @@ class X2goClient(object):
         @rtype: C{bool}
 
         """
-        return self.session_registry(session_uuid).connect(username=username, password=password, 
-                                                           add_to_known_hosts=add_to_known_hosts, 
+        return self.session_registry(session_uuid).connect(username=username, password=password,
+                                                           add_to_known_hosts=add_to_known_hosts,
                                                            force_password_auth=force_password_auth,
                                                           )
     __connect_session = connect_session
@@ -667,7 +673,7 @@ class X2goClient(object):
         @type session_uuid: C{str}
         """
         self.session_registry(session_uuid).disconnect()
-        if self.use_cache:
+        if self.use_listsessions_cache:
             self.__update_cache_all_profiles()
     __disconnect_session = disconnect_session
 
@@ -727,7 +733,7 @@ class X2goClient(object):
         return self.session_registry(session_uuid).start()
     __start_session = start_session
 
-    def resume_session(self, session_uuid, session_name):
+    def resume_session(self, session_uuid=None, session_name=None):
         """\
         Resume or continue a suspended / running X2go session on a
         remote X2go server (as specified when L{register_session} was
@@ -742,7 +748,15 @@ class X2goClient(object):
         @rtype: C{bool}
 
         """
-        return self.session_registry(session_uuid).resume(session_name)
+        if session_uuid is None and session_name is None:
+            raise x2go_exceptions.X2goClientException('can\'t resume a session without either session_uuid or session_name')
+        if session_name is None and self.session_registry(session_uuid).session_name is None:
+            raise x2go_exceptions.X2goClientException('don\'t know which session to resume')
+        if session_uuid is None:
+            session_uuid = self.session_registry.get_session_of_session_name(session_name=session_name, return_object=False)
+            return self.session_registry(session_uuid).resume()
+        else:
+            return self.session_registry(session_uuid).resume(session_name=session_name)
     __resume_session = resume_session
 
     def suspend_session(self, session_uuid, session_name=None):
@@ -775,7 +789,7 @@ class X2goClient(object):
         if session_name is None:
             return self.session_registry(session_uuid).suspend()
         else:
-            for session in self.session_registry.running_sessions:
+            for session in self.session_registry.running_sessions():
                 if session_name == session.get_session_name():
                     return session.suspend()
         return self.session_registry(session_uuid).control_session.suspend(session_name=session_name)
@@ -814,7 +828,7 @@ class X2goClient(object):
         if session_name is None:
             return self.session_registry(session_uuid).terminate()
         else:
-            for session in self.session_registry.running_sessions + self.session_registry.suspended_sessions:
+            for session in self.session_registry.running_sessions() + self.session_registry.suspended_sessions():
                 if session_name == session.get_session_name():
                     return session.terminate()
         return self.session_registry(session_uuid).control_session.terminate(session_name=session_name)
@@ -979,21 +993,7 @@ class X2goClient(object):
         STILL UNDOCUMENTED
 
         """
-        if return_objects:
-            return [ obj for obj in self.session_registry.connected_sessions ]
-        if return_profile_names:
-            return [ obj.get_profile_name() for obj in self.session_registry.connected_sessions ]
-        return [ obj() for obj in self.session_registry.connected_sessions ]
-    __client_connected_sessions = client_connected_sessions
-
-    def client_connected_sessions_of_name(self, profile_name, return_objects=False):
-        """\
-        STILL UNDOCUMENTED
-
-        """
-        if return_objects:
-            return [ s for s in self.session_registry.connected_sessions if s.get_profile_name() == profile_name ]
-        return [ s.get_uuid() for s in self.session_registry.connected_sessions if s.get_profile_name() == profile_name ]
+        return self.session_registry.connected_sessions(return_objects=return_objects, return_profile_names=return_profile_names)
     __client_connected_sessions = client_connected_sessions
 
     @property
@@ -1010,11 +1010,7 @@ class X2goClient(object):
         STILL UNDOCUMENTED
 
         """
-        if return_objects:
-            return [ obj for obj in self.session_registry.running_sessions ]
-        if return_profile_names:
-            return [ obj.get_profile_name() for obj in self.session_registry.running_sessions ]
-        return [ obj.get_uuid() for obj in self.session_registry.running_sessions ]
+        return self.session_registry.running_sessions(return_objects=return_objects, return_profile_names=return_profile_names)
     __client_running_sessions = client_running_sessions
 
     @property
@@ -1031,11 +1027,7 @@ class X2goClient(object):
         STILL UNDOCUMENTED
 
         """
-        if return_objects:
-            return [ obj for obj in self.session_registry.suspended_sessions ]
-        if return_profile_names:
-            return [ obj.get_profile_name() for obj in self.session_registry.suspended_sessions ]
-        return [ obj.get_uuid() for obj in self.session_registry.suspended_sessions ]
+        return self.session_registry.running_sessions(return_objects=return_objects, return_profile_names=return_profile_names)
     __client_suspended_sessions = client_suspended_sessions
 
     @property
@@ -1048,12 +1040,12 @@ class X2goClient(object):
     __client_has_suspended_sessions = client_has_suspended_sessions
 
     @property
-    def client_registered_sessions(self):
+    def client_registered_sessions(self, return_objects=True, return_profile_names=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self.session_registry.registered_sessions
+        return self.session_registry.registered_sessions(return_objects=return_objects, return_profile_names=return_profile_names)
     __client_registered_sessions = client_registered_sessions
 
     @property
@@ -1065,21 +1057,45 @@ class X2goClient(object):
         return self.session_registry.control_sessions
     __client_control_sessions = client_control_sessions
 
-    def client_control_session_of_name(self, profile_name):
+    def client_control_session_of_profile_name(self, profile_name):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self.session_registry.control_session_of_name(profile_name)
-    __client_control_session_of_name = client_control_session_of_name
+        return self.session_registry.control_session_of_profile_name(profile_name)
+    __client_control_session_of_profile_name = client_control_session_of_profile_name
 
-    def client_registered_sessions_of_name(self, profile_name):
+    def client_registered_session_of_name(self, session_name, return_object=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self.session_registry.registered_sessions_of_name(profile_name)
-    __client_registered_sessions_of_name = client_registered_sessions_of_name
+        return self.session_registry.get_session_of_session_name(session_name, return_object=return_object)
+    __client_registered_session_of_name = client_registered_session_of_name
+
+    def client_has_registered_session_of_name(self, session_name):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.client_registered_session_of_name(session_name) is not None
+    __client_has_registered_session_of_name = client_registered_session_of_name
+
+    def client_registered_sessions_of_profile_name(self, profile_name, return_objects=False):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.session_registry.registered_sessions_of_profile_name(profile_name, return_objects=return_objects)
+    __client_registered_sessions_of_profile_name = client_registered_sessions_of_profile_name
+
+    def client_connected_sessions_of_profile_name(self, profile_name, return_objects=False):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.session_registry.connected_sessions_of_profile_name(profile_name, return_objects=return_objects)
+    __client_connected_sessions = client_connected_sessions
 
     ###
     ### Provide access to the X2go server's sessions DB
@@ -1129,7 +1145,7 @@ class X2goClient(object):
             session_list = self._X2goClient__list_sessions(session_uuid)
             return [ key for key in session_list.keys() if session_list[key].status == 'R' ]
         else:
-            raise X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
+            raise x2go_exceptions.X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
     __server_running_sessions = server_running_sessions
 
     @property
@@ -1158,7 +1174,7 @@ class X2goClient(object):
             session_list = self._X2goClient__list_sessions(session_uuid)
             return [ key for key in session_list.keys() if session_list[key].status == 'S' ]
         else:
-            raise X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
+            raise x2go_exceptions.X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
     __server_suspended_sessions = server_suspended_sessions
 
     @property
@@ -1199,7 +1215,11 @@ class X2goClient(object):
         session.clean_sessions()
     __clean_sessions = clean_sessions
 
-    def list_sessions(self, session_uuid, no_cache=False, refresh_cache=False):
+    def list_sessions(self, session_uuid=None, 
+                      profile_name=None, profile_id=None, 
+                      no_cache=False, refresh_cache=False, 
+                      update_sessionregistry=True,
+                      register_sessions=False):
         """\
         Use the X2go session registered under C{session_uuid} to
         retrieve a list of running or suspended X2go sessions on the 
@@ -1214,19 +1234,45 @@ class X2goClient(object):
         @type session_uuid: C{str}
 
         """
-        session = self.session_registry(session_uuid)
+        if profile_id is not None:
+            profile_name = self.to_profile_name(profile_id)
+
+        if profile_name is not None:
+
+            _connected_sessions = self.client_connected_sessions_of_profile_name(profile_name, return_objects=True)
+            if _connected_sessions:
+                # it does not really matter which session to use for getting a server-side session list
+                # thus, we simply grab the first that comes in...
+                session_uuid = _connected_sessions[0].get_uuid()
+            else:
+                raise x2go_exceptions.X2goClientException('profile ,,%s\'\' is not connected' % profile_name)
 
-        if not self.use_cache or no_cache:
-            return session.list_sessions()
+        elif session_uuid is not None:
+            pass
+        else:
+            raise x2go_exceptions.X2goClientException('must either specify session UUID or profile name')
+
+        if not self.use_listsessions_cache or no_cache:
+            _session_list = self.session_registry(session_uuid).list_sessions()
         elif refresh_cache:
             self.update_cache_by_session_uuid(session_uuid)
-            return self.listsessions_cache.list_sessions(session_uuid)
+            _session_list = self.listsessions_cache.list_sessions(session_uuid)
         else:
             # if there is no cache for this session_uuid available, make sure the cache gets updated
             # before reading from it...
-            if self.use_cache and (not self.listsessions_cache.is_cached(session_uuid=session_uuid)):
+            if self.use_listsessions_cache and (not self.listsessions_cache.is_cached(session_uuid=session_uuid)):
                 self.__update_cache_by_session_uuid(session_uuid)
-            return self.listsessions_cache.list_sessions(session_uuid)
+            _session_list = self.listsessions_cache.list_sessions(session_uuid)
+
+        if update_sessionregistry:
+            self.session_registry.update_status(profile_name=self.get_session_profile_name(session_uuid), session_list=_session_list)
+
+        if register_sessions:
+            self.session_registry.register_available_server_sessions(profile_name=self.get_session_profile_name(session_uuid),
+                                                                     session_list=_session_list, 
+                                                                     update_sessionregistry=False)
+
+        return _session_list
     __list_sessions = list_sessions
 
     ###
@@ -1363,43 +1409,109 @@ class X2goClient(object):
         @param profile_name: the X2go session profile name
         @type profile_name: C{str}
         """
-        for s in self.session_registry.registered_sessions_of_name(profile_name):
+        for s in self.session_registry.registered_sessions_of_profile_name(profile_name, return_objects=True):
             s.disconnect()
-        if self.use_cache:
+        if self.use_listsessions_cache:
             self.__update_cache_all_profiles()
     __disconnect_profile = disconnect_profile
 
-    def update_cache_by_profile(self, profile_name, seconds=None):
+    def update_sessionregistry_status_by_profile_name(self, profile_name):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        session_uuids = self.client_registered_sessions_of_profile_name(profile_name)
+        if session_uuids:
+            session_list = self.list_sessions(session_uuids[0],
+                                              update_sessionregistry=False, 
+                                              register_sessions=False,
+                                             )
+            self.session_registry.update_status(profile_name=profile_name, session_list=session_list)
+    __update_sessionregistry_status_by_profile_name = update_sessionregistry_status_by_profile_name
+
+
+    def update_sessionregistry_status_by_session_uuid(self, session_uuid):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        session_list = self.list_sessions(session_uuid, update_sessionregistry=False, register_sessions=False)
+        if session_list:
+            self.session_registry.update_status(session_uuid=session_uuid, session_list=session_list)
+    __update_sessionregistry_status_by_session_uuid = update_sessionregistry_status_by_session_uuid
+
+    def update_sessionregistry_status_all_profiles(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        for profile_name in self.connected_profiles(return_profile_names=True):
+            self.__update_sessionregistry_status_by_profile_name(profile_name)
+    __update_sessionregistry_status_all_profiles = update_sessionregistry_status_all_profiles
+
+
+    def update_cache_by_profile_name(self, profile_name):
         """\
         STILL UNDOCUMENTED
 
         """
         if self.listsessions_cache is not None:
             try:
-                self.listsessions_cache.update(profile_name, seconds=seconds)
+                self.listsessions_cache.update(profile_name)
             except x2go_exceptions.X2goControlSessionException:
                 self.HOOK_on_control_session_death(profile_name)
                 self.disconnect_profile(profile_name)
                 return False
-    __update_cache_by_profile = update_cache_by_profile
+    __update_cache_by_profile_name = update_cache_by_profile_name
 
-    def update_cache_by_session_uuid(self, session_uuid, seconds=None):
+    def update_cache_by_session_uuid(self, session_uuid):
         """\
         STILL UNDOCUMENTED
 
         """
         profile_name = self.get_session_profile_name(session_uuid)
-        self.__update_cache_by_profile(profile_name, seconds=seconds)
+        self.__update_cache_by_profile_name(profile_name)
     __update_cache_by_session_uuid = update_cache_by_session_uuid
 
-    def update_cache_all_profiles(self, seconds=None):
+    def update_cache_all_profiles(self):
         """\
         STILL UNDOCUMENTED
 
         """
         if self.listsessions_cache is not None:
             for profile_name in self.connected_profiles(return_profile_names=True):
-                self.__update_cache_by_profile(profile_name, seconds=seconds)
+                self.__update_cache_by_profile_name(profile_name)
 
-            self.listsessions_cache.check_cache(seconds=seconds)
+            self.listsessions_cache.check_cache()
     __update_cache_all_profiles = update_cache_all_profiles
+
+    def register_available_server_sessions_by_profile_name(self, profile_name):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        for profile_name in self.connected_profiles(return_profile_names=True):
+            session_list = self.list_sessions(profile_name=profile_name, 
+                                              update_sessionregistry=False,
+                                              register_sessions=False,
+                                             )
+            self.session_registry.register_available_server_sessions(profile_name, session_list=session_list)
+    __register_available_server_sessions_by_profile_name = register_available_server_sessions_by_profile_name
+
+    def register_available_server_sessions_by_session_uuid(self, session_uuid):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        profile_name = self.get_session_profile_name(session_uuid)
+        self.__register_available_server_sessions_by_profile_name(profile_name)
+    __register_available_server_sessions_by_session_uuid = register_available_server_sessions_by_session_uuid
+
+    def register_available_server_sessions_all_profiles(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        for profile_name in self.connected_profiles(return_profile_names=True):
+            self.__register_available_server_sessions_by_profile_name(profile_name)
+    __register_available_server_sessions_all_profiles = register_available_server_sessions_all_profiles
diff --git a/x2go/defaults.py b/x2go/defaults.py
index 69cbbbc..dd90ee2 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
@@ -234,17 +234,18 @@ else:
 X2GO_SESSIONPROFILE_DEFAULTS = {
     'speed': 2, 'pack': '16m-jpeg', 'quality': 9, 'link':'ADSL',
     'iconvto': 'UTF-8', 'iconvfrom': 'ISO-8859-15', 'useiconv': False,
+    'usesshproxy': False, 'sshproxy': '',
     'fstunnel': True,
     'export': '',
     'fullscreen': False,
     'width': 800,'height': 600,'dpi': 96,'setdpi': False,
     'usekbd':True, 'layout': 'us', 'type': 'pc105/us',
-    'sound':False, 'soundsystem': 'pulse', 'startsoundsystem': True, 'soundtunnel':True, 'defsndport':True, 'sndport':4713, 
-    'name': None, 'icon': ':icons/128x128/x2gosession.png', 
-    'host': None, 'user': None, 'key': None, 'sshport': 22, 'add_to_known_hosts': True,
-    'rootless': True, 'applications': 'WWWBROWSER, MAILCLIENT, OFFICE, TERMINAL', 'command':'TERMINAL', 'session_type': 'application',
-    'rdpoptions':None, 'rdpserver':None, 
-    'print': True,
+    'sound':False, 'soundsystem': 'pulse', 'startsoundsystem': False, 'soundtunnel':True, 'defsndport':True, 'sndport':4713, 
+    'name': '', 'icon': ':icons/128x128/x2gosession.png', 
+    'host': '', 'user': CURRENT_LOCAL_USER, 'key': '', 'sshport': 22,
+    'rootless': True, 'applications': 'WWWBROWSER, MAILCLIENT, OFFICE, TERMINAL', 'command':'TERMINAL',
+    'rdpoptions': '-u X2GO_USER -p X2GO_PASSWORD', 'rdpserver': '',
+    'print': False,
     'xdmcpserver': 'localhost',
     }
 """L{X2goSessionProfiles} default values to fill a new session profile with."""
diff --git a/x2go/guardian.py b/x2go/guardian.py
index 27b11f4..f55dd4f 100644
--- a/x2go/guardian.py
+++ b/x2go/guardian.py
@@ -50,7 +50,12 @@ class X2goSessionGuardian(threading.Thread):
 
     """
 
-    def __init__(self, client, enable_cache=True, logger=None, loglevel=log.loglevel_DEFAULT):
+    def __init__(self, client_instance, 
+                 auto_update_listsessions_cache=False, 
+                 auto_update_sessionregistry=False,
+                 auto_register_sessions=False,
+                 refresh_interval=5,
+                 logger=None, loglevel=log.loglevel_DEFAULT):
         """\
         @param enable_cache: let L{X2goSessionGuardian} refresh the session list cache for all L{X2goSession} objects
         @type enable_cache: C{bool}
@@ -67,8 +72,12 @@ class X2goSessionGuardian(threading.Thread):
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
-        self.client = client
-        self.enable_cache = enable_cache
+        self.client_instance = client_instance
+        self.auto_update_listsessions_cache = auto_update_listsessions_cache
+        self.auto_update_sessionregistry = auto_update_sessionregistry
+        self.auto_register_sessions = auto_register_sessions
+        self.refresh_interval = refresh_interval
+
         threading.Thread.__init__(self, target=self.guardian)
         self.daemon = True
         self.start()
@@ -86,19 +95,21 @@ class X2goSessionGuardian(threading.Thread):
             gevent.sleep(1)
             seconds += 1
 
-            if seconds % 5 == 0:
-                # if no cache is used the next command acts like a ping a each session
-                # if any of the connected servers is dead an X2goClient.disconnect_profile()
-                # call will be executed on the respective session profile.
-                self.client.all_servers_are_alive()
+            if seconds % self.refresh_interval == 0:
+
+                if self.auto_update_listsessions_cache:
+                    self.client_instance.update_cache_all_profiles()
+
+                if self.auto_update_sessionregistry:
+                    self.client_instance.update_sessionregistry_status_all_profiles()
 
-            if self.enable_cache:
-                self.client.update_cache_all_profiles(seconds=seconds)
+                if self.auto_register_sessions:
+                    self.client_instance.register_available_server_sessions_all_profiles()
 
         self.logger('X2go session guardian thread waking up after %s seconds' % seconds, loglevel=log.loglevel_DEBUG)
 
-        for session_uuid in self.client.session_registry.keys():
-            session_summary = self.client.get_session_summary(session_uuid)
+        for session_uuid in self.client_instance.session_registry.keys():
+            session_summary = self.client_instance.get_session_summary(session_uuid)
             self.logger('calling session cleanup on profile %s for terminal session: %s' % (session_summary['profile_name'], session_summary['session_name']), loglevel=log.loglevel_DEBUG)
             x2go_cleanup(threads=session_summary['active_threads'])
 
diff --git a/x2go/inifiles.py b/x2go/inifiles.py
index 7762005..88ca068 100644
--- a/x2go/inifiles.py
+++ b/x2go/inifiles.py
@@ -183,7 +183,7 @@ class X2goIniFile(object):
             fd = open(self.user_config_file, 'wb')
             self.iniConfig.write(fd)
             fd.close()
-            self.write_config = False
+            self.write_user_config = False
 
     def get_type(self, section, key):
         """\
diff --git a/x2go/registry.py b/x2go/registry.py
index 66f6af3..53f934f 100644
--- a/x2go/registry.py
+++ b/x2go/registry.py
@@ -54,7 +54,7 @@ class X2goSessionRegistry(object):
     STILL UNDOCUMENTED
 
     """
-    def __init__(self, use_cache=True, 
+    def __init__(self, client_instance,
                  logger=None, loglevel=log.loglevel_DEFAULT):
         """\
         STILL UNDOCUMENTED
@@ -66,6 +66,8 @@ class X2goSessionRegistry(object):
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
+        self.client_instance = client_instance
+
         self.registry = {}
         self.control_sessions = {}
 
@@ -88,44 +90,158 @@ class X2goSessionRegistry(object):
         STILL UNDOCUMENTED
 
         """
-        return self(session_uid).profile.profile_id
+        return self(session_uuid).get_profile_id()
 
     def get_profile_name(self, session_uuid):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self(session_uuid).profile.profile_name
+        return self(session_uuid).get_profile_name()
 
-    def session_summary(self, session_uuid):
+    def session_summary(self, session_uuid, status_only=False):
         """\
         STILL UNDOCUMENTED
 
         """
         _session_summary = {}
-        _session_summary['uuid'] = session_uuid
-        _session_summary['profile_id'] = self.get_profile_id(session_uuid)
-        _session_summary['profile_name'] = self.get_profile_name(session_uuid)
-        _session_summary['session_name'] = self(session_uuid).get_session_name()
-        _session_summary['control_session'] = self(session_uuid).get_control_session()
-        _session_summary['control_params'] = self(session_uuid).control_params
-        _session_summary['terminal_session'] = self(session_uuid).get_terminal_session()
-        _session_summary['terminal_params'] = self(session_uuid).terminal_params
-        _session_summary['active_threads'] = self(session_uuid).get_terminal_session().active_threads
-        _session_summary['connected'] = self(session_uuid).connected
-        _session_summary['running'] = self(session_uuid).running
-        _session_summary['suspended'] = self(session_uuid).suspended
-        _session_summary['terminated'] = self(session_uuid).terminated
-        _session_summary['backends'] = {
-            'control': self(session_uuid)._control_backend,
-            'terminal': self(session_uuid)._terminal_backend,
-            'info': self(session_uuid)._info_backend,
-            'list': self(session_uuid)._list_backend,
-            'proxy': self(session_uuid)._proxy_backend,
-        }
+        _r = False
+        if session_uuid in [ s() for s in self.registered_sessions() ]:
+            _r = True
+
+        if not status_only:
+            _session_summary['uuid'] = _r and session_uuid or None
+            _session_summary['profile_id'] = _r and self.get_profile_id(session_uuid) or ''
+            _session_summary['profile_name'] = _r and self.get_profile_name(session_uuid) or ''
+            _session_summary['session_name'] = _r and self(session_uuid).get_session_name() or ''
+            _session_summary['control_session'] = _r and self(session_uuid).get_control_session() or None
+            _session_summary['control_params'] = _r and self(session_uuid).control_params or {}
+            _session_summary['terminal_session'] = _r and self(session_uuid).get_terminal_session() or None
+            _session_summary['terminal_params'] = _r and self(session_uuid).terminal_params or {}
+            _session_summary['active_threads'] = _r and self(session_uuid).get_terminal_session().active_threads or []
+            _session_summary['backends'] = {
+                'control': _r and self(session_uuid)._control_backend or None,
+                'terminal': _r and self(session_uuid)._terminal_backend or None,
+                'info': _r and self(session_uuid)._info_backend or None,
+                'list': _r and self(session_uuid)._list_backend or None,
+                'proxy': _r and self(session_uuid)._proxy_backend or None,
+            }
+
+        if _r:
+            _session_summary['virgin'] = self(session_uuid).virgin
+            _session_summary['connected'] = self(session_uuid).connected
+            _session_summary['running'] = self(session_uuid).running
+            _session_summary['suspended'] = self(session_uuid).suspended
+            _session_summary['terminated'] = self(session_uuid).terminated
+        else:
+            _session_summary['virgin'] = None
+            _session_summary['connected'] = None
+            _session_summary['running'] = None
+            _session_summary['suspended'] = None
+            _session_summary['terminated'] = None
         return _session_summary
 
-    def register(self, server, profile_id, profile_name, 
+    def update_status(self, session_uuid=None, profile_name=None, profile_id=None, session_list=None):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        if session_uuid and profile_name or session_uuid and profile_id or profile_name and profile_id:
+            raise X2goSessionRegistryException('only one of the possible method parameters is allowed (session_uuid, profile_name or profile_id)')
+        elif session_uuid is None and profile_name is None and profile_id is None:
+            raise X2goSessionRegistryException('at least one of the method parameters session_uuid, profile_name or profile_id must be given')
+
+        if session_uuid:
+            session_uuids = [ session_uuid ]
+        elif profile_name:
+            session_uuids = [ s() for s in self.registered_sessions_of_profile_name(profile_name, return_objects=True) ]
+        elif profile_id:
+            session_uuids = [ s() for s in self.registered_sessions_of_profile_name(self.client_instance.to_profile_name(profile_id), return_objects=True) ]
+
+        for _session_uuid in session_uuids:
+            self(_session_uuid).update_status(session_list=session_list)
+            _last_status = copy.deepcopy(self(_session_uuid)._last_status)
+            _current_status = copy.deepcopy(self(_session_uuid)._current_status)
+
+            # at this point we hook into the X2goClient instance and call notification methods
+            # that can be used to inform an application that something has happened
+
+            _profile_name = self(_session_uuid).get_profile_name()
+            _session_name = self(_session_uuid).get_session_name()
+
+            if _last_status['running'] == False and _current_status['running'] == True:
+                # session has started
+                if self(_session_uuid).has_terminal_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)
+                    else:
+                        # as a new session
+                        self.client_instance.HOOK_on_session_has_started_by_me(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+                else:
+                    if _last_status['suspended']:
+                        # from a suspended state
+                        self.client_instance.HOOK_on_session_has_resumed_by_other(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+                    else:
+                        # as a new session
+                        self.client_instance.HOOK_on_session_has_started_by_other(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+            elif _last_status['suspended'] == False and _current_status['suspended'] == True:
+                # session has been suspended
+                self(_session_uuid).session_cleanup()
+                self.client_instance.HOOK_on_session_has_been_suspended(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+            elif _last_status['terminated'] == False and _current_status['terminated'] == True:
+                # session has terminated
+                self.client_instance.HOOK_on_session_has_terminated(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+                self(_session_uuid).session_cleanup()
+                self(_session_uuid).__del__()
+                if len(self.virgin_sessions_of_profile_name(profile_name)) > 1:
+                    del self.registry[_session_uuid]
+
+    def register_available_server_sessions(self, profile_name, session_list=None):
+
+        _connected_sessions = self.connected_sessions_of_profile_name(profile_name=profile_name, return_objects=False)
+        _registered_sessions = self.registered_sessions_of_profile_name(profile_name=profile_name, return_objects=False)
+        _session_names = [ self(s_uuid).session_name for s_uuid in _registered_sessions if self(s_uuid).session_name is not None ]
+
+        if _connected_sessions:
+            # any of the connected sessions is valuable for accessing the profile's control 
+            # session commands, so we simply take the first that comes in...
+            _ctrl_session = self(_connected_sessions[0])
+            if session_list is None:
+                session_list = _ctrl_session.list_sessions()
+            for session_name in session_list.keys():
+                if session_name not in _session_names:
+                    server = _ctrl_session.get_server_hostname()
+                    profile_id = _ctrl_session.get_profile_id()
+
+                    # reconstruct all session options of _ctrl_session to auto-register a suspended session
+                    # found on the _ctrl_session's connected server
+                    _pre_kwargs = _ctrl_session.__dict__
+                    kwargs = {}
+                    kwargs.update(_pre_kwargs['terminal_params'])
+                    kwargs.update(_pre_kwargs['control_params'])
+                    kwargs['control_backend'] = _pre_kwargs['_control_backend']
+                    kwargs['terminal_backend'] = _pre_kwargs['_terminal_backend']
+                    kwargs['proxy_backend'] = _pre_kwargs['_proxy_backend']
+                    kwargs['info_backend'] = _pre_kwargs['_info_backend']
+                    kwargs['list_backend'] = _pre_kwargs['_list_backend']
+                    kwargs['settings_backend'] = _pre_kwargs['_settings_backend']
+                    kwargs['printing_backend'] = _pre_kwargs['_printing_backend']
+                    kwargs['keep_controlsession_alive'] = _pre_kwargs['keep_controlsession_alive']
+                    kwargs['client_rootdir'] = _pre_kwargs['client_rootdir']
+                    kwargs['sessions_rootdir'] = _pre_kwargs['sessions_rootdir']
+
+                    # this if clause catches problems when x2golistsessions commands give weird results
+                    if not self.has_session_of_session_name(session_name):
+                        self.register(server, profile_id, profile_name, 
+                                      session_name=session_name,
+                                      virgin=False, running=False, suspended=True, terminated=None,
+                                      **kwargs
+                                     )
+                        self.update_status(profile_name=profile_name, session_list=session_list)
+
+    def register(self, server, profile_id, profile_name,
+                 session_name=None,
                  control_backend=_X2goControlSession,
                  terminal_backend=_X2goTerminalSession,
                  info_backend=_X2goServerSessionInfo,
@@ -136,14 +252,36 @@ class X2goSessionRegistry(object):
                  client_rootdir=os.path.join(_LOCAL_HOME,_X2GO_CLIENT_ROOTDIR),
                  sessions_rootdir=os.path.join(_LOCAL_HOME,_X2GO_SESSIONS_ROOTDIR),
                  ssh_rootdir=os.path.join(_LOCAL_HOME,_X2GO_SSH_ROOTDIR),
+                 keep_controlsession_alive=True,
                  **kwargs):
+        """\
+        STILL UNDOCUMENTED
 
+        """
         control_session = None
         if profile_id in self.control_sessions.keys():
             control_session = self.control_sessions[profile_id]
 
+        # when starting a new session, we will try to use unused registered virgin sessions
+        # depending on your application layout, there shoul either be one or no such virgin session at all
+        _virgin_sessions = self.virgin_sessions_of_profile_name(profile_name, return_objects=True)
+        if _virgin_sessions and not session_name:
+
+            session_uuid = _virgin_sessions[0].get_uuid()
+            self.logger('using already initially-registered yet-unused session %s' % session_uuid, log.loglevel_NOTICE)
+            return session_uuid
+
+        try:
+            _retval = self.get_session_of_session_name(session_name)
+            self.logger('using already registered-by-session-name session %s' % session_uuid, log.loglevel_NOTICE)
+            return _retval
+        except X2goSessionException:
+            # no registered session for session_name found... FINE, go ahead!
+            pass
+
         s = session.X2goSession(server=server, control_session=control_session,
                                 profile_id=profile_id, profile_name=profile_name,
+                                session_name=session_name,
                                 control_backend=control_backend,
                                 terminal_backend=terminal_backend,
                                 info_backend=info_backend,
@@ -154,6 +292,7 @@ class X2goSessionRegistry(object):
                                 client_rootdir=client_rootdir,
                                 sessions_rootdir=sessions_rootdir,
                                 ssh_rootdir=ssh_rootdir,
+                                keep_controlsession_alive=keep_controlsession_alive,
                                 logger=self.logger, **kwargs)
 
         session_uuid = s._X2goSession__get_uuid()
@@ -166,48 +305,81 @@ class X2goSessionRegistry(object):
 
         return session_uuid
 
-    def _sessionsWithState(self, state):
-        return [ ts for ts in self.registry.values() if eval('ts.%s' % state) ]
+    def has_session_of_session_name(self, session_name):
+        """\
+        STILL UNDOCUMENTED
 
-    @property
-    def connected_sessions(self):
+        """
+        try:
+            _dummy = self.get_session_of_session_name(session_name)
+            return True
+        except X2goSessionException:
+            return False
+
+    def get_session_of_session_name(self, session_name, return_object=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self._sessionsWithState('connected')
+        found_sessions = [ s for s in self.registered_sessions() if s.session_name == session_name and s.session_name is not None ]
+        if len(found_sessions) == 1:
+            session = found_sessions[0]
+            if return_object:
+                return session
+            else:
+                return session.get_uuid()
+        elif len(found_sessions) > 1:
+            raise X2goSessionRegistryException('there should only be one registered session of name ,,%s\'\'' % session_name)
+        else:
+            raise X2goSessionException('no session of name ,,%s\'\' registered' % session_name)
+
+    def _sessionsWithState(self, state, return_objects=True, return_profile_names=False):
+        sessions = [ ts for ts in self.registry.values() if eval('ts.%s' % state) ]
+        if return_objects:
+            return sessions
+        elif return_profile_names:
+            profile_names = []
+            for session in sessions:
+                if session.profile_name not in profile_names:
+                    profile_names.append(session.profile_name)
+            return profile_names
+        else:
+            return [s.get_uuid() for s in sessions ]
 
-    @property
-    def connected_sessions(self):
+    def connected_sessions(self, return_objects=True, return_profile_names=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self._sessionsWithState('connected')
+        return self._sessionsWithState('connected', return_objects=return_objects, return_profile_names=return_profile_names)
 
-    @property
-    def running_sessions(self):
+    def virgin_sessions(self, return_objects=True, return_profile_names=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self._sessionsWithState('running')
+        return self._sessionsWithState('virgin', return_objects=return_objects, return_profile_names=return_profile_names)
 
-    @property
-    def suspended_sessions(self):
+    def running_sessions(self, return_objects=True, return_profile_names=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self._sessionsWithState('suspended')
+        return self._sessionsWithState('running', return_objects=return_objects, return_profile_names=return_profile_names)
 
-    @property
-    def terminated_sessions(self):
+    def suspended_sessions(self, return_objects=True, return_profile_names=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self._sessionsWithState('terminated')
+        return self._sessionsWithState('suspended', return_objects=return_objects, return_profile_names=return_profile_names)
+
+    def terminated_sessions(self, return_objects=True, return_profile_names=False):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self._sessionsWithState('terminated', return_objects=return_objects, return_profile_names=return_profile_names)
 
     @property
     def has_running_sessions(self):
@@ -215,7 +387,7 @@ class X2goSessionRegistry(object):
         STILL UNDOCUMENTED
 
         """
-        return self.running_sessions and len(self.running_sessions) > 0
+        return self.running_sessions() and len(self.running_sessions()) > 0
 
     @property
     def has_suspended_sessions(self):
@@ -225,13 +397,21 @@ class X2goSessionRegistry(object):
         """
         return self.suspended_sessions and len(self.suspended_sessions) > 0
 
-    @property
-    def registered_sessions(self):
+    def registered_sessions(self, return_objects=True, return_profile_names=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self.registry.values()
+        if return_objects:
+            return self.registry.values()
+        elif return_profile_names:
+            profile_names = []
+            for session in self.registry.values():
+                if session.profile_name not in profile_names:
+                    profile_names.append(profile_name)
+            return profile_names
+        else:
+            return self.registry.keys()
 
     @property
     def non_running_sessions(self):
@@ -239,36 +419,65 @@ class X2goSessionRegistry(object):
         STILL UNDOCUMENTED
 
         """
-        return [ s for s in self.registry.values() if s not in self.running_sessions ]
+        return [ s for s in self.registry.values() if s not in self.running_sessions() ]
+
+    def connected_sessions_of_profile_name(self, profile_name, return_objects=False):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        if return_objects:
+            return self.connected_sessions() and [ s for s in self.connected_sessions() if s.profile_name == profile_name ]
+        else:
+            return self.connected_sessions() and [ s.get_uuid() for s in self.connected_sessions() if s.profile_name == profile_name ]
 
-    def registered_sessions_of_name(self, profile_name):
+    def registered_sessions_of_profile_name(self, profile_name, return_objects=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self.registered_sessions and [ s for s in self.registered_sessions if s.profile_name == profile_name ]
 
-    def running_sessions_of_name(self, profile_name):
+        if return_objects:
+            return self.registered_sessions() and [ s for s in self.registered_sessions() if s.profile_name == profile_name ]
+        else:
+            return self.registered_sessions() and [ s.get_uuid() for s in self.registered_sessions() if s.profile_name == profile_name ]
+
+    def virgin_sessions_of_profile_name(self, profile_name, return_objects=False):
+
+        if return_objects:
+            return self.virgin_sessions() and [ s for s in self.virgin_sessions() if s.profile_name == profile_name ]
+        else:
+            return self.virgin_sessions() and [ s.get_uuid() for s in self.virgin_sessions() if s.profile_name == profile_name ]
+
+
+    def running_sessions_of_profile_name(self, profile_name, return_objects=False):
         """\
         STILL UNDOCUMENTED
 
         """
-        return self.running_sessions and [ s for s in self.running_sessions if s.profile_name == profile_name ]
+        if return_objects:
+            return self.running_sessions() and [ s for s in self.running_sessions() if s.profile_name == profile_name ]
+        else:
+            return self.running_sessions() and [ s.get_uuid() for s in self.running_sessions() if s.profile_name == profile_name ]
 
-    def suspended_sessions_of_name(self, profile_name):
+    def suspended_sessions_of_profile_name(self, profile_name, return_objects=False):
         """\
         STILL UNDOCUMENTED
 
-            """
-        return self.running_sessions and [ s for s in self.running_sessions if s.profile_name == profile_name ]
+        """
+        if return_objects:
+            return self.suspended_sessions() and [ s for s in self.suspended_sessions() if s.profile_name == profile_name ]
+        else:
+            return self.suspended_sessions() and [ s.get_uuid() for s in self.suspended_sessions() if s.profile_name == profile_name ]
 
-    def control_session_of_name(self, profile_name):
+    def control_session_of_profile_name(self, profile_name):
         """\
         STILL UNDOCUMENTED
 
         """
-        if self.registered_sessions_of_name(profile_name):
-            session = self.registered_sessions_of_name(profile_name)[0]
+        _sessions = self.registered_sessions_of_profile_name(profile_name, return_objects=True)
+        if _sessions:
+            session = _sessions[0]
             return session.control_session
         return None
 
diff --git a/x2go/session.py b/x2go/session.py
index 08248a0..bab60b0 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -68,6 +68,7 @@ class X2goSession(object):
 
     def __init__(self, server=None, control_session=None,
                  profile_id=None, profile_name='UNKNOWN',
+                 session_name=None,
                  printing=None, share_local_folders=[],
                  control_backend=_X2goControlSession,
                  terminal_backend=_X2goTerminalSession,
@@ -80,7 +81,9 @@ class X2goSession(object):
                  sessions_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SESSIONS_ROOTDIR),
                  ssh_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SSH_ROOTDIR),
                  known_hosts=None,
+                 keep_controlsession_alive=False,
                  logger=None, loglevel=log.loglevel_DEFAULT,
+                 virgin=True, running=None, suspended=None, terminated=None,
                  **params):
 
         if logger is None:
@@ -89,16 +92,29 @@ class X2goSession(object):
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
-        self._keep_alive = True
+        self._keep = None
 
         self.uuid = uuid.uuid1()
         self.connected = False
-        self.running = False
-        self.suspended = False
-        self.terminated = False
+
+        self.virgin = virgin
+        self.running = running
+        self.suspended = suspended
+        self.terminated = terminated
+        self.keep_controlsession_alive = keep_controlsession_alive
+
+        self._current_status = {
+            'virgin': self.virgin,
+            'connected': self.connected,
+            'running': self.running,
+            'suspended': self.suspended,
+            'terminated': self.terminated,
+        }
+        self._last_status = None
 
         self.profile_id = profile_id
         self.profile_name = profile_name
+        self.session_name = session_name
         self.server = server
         self.printing = printing
         self.share_local_folders = share_local_folders
@@ -158,6 +174,7 @@ class X2goSession(object):
         if known_hosts:
             self.control_session.load_host_keys(known_hosts)
 
+
     def __str__(self):
         return self.__get_uuid()
 
@@ -171,6 +188,38 @@ class X2goSession(object):
     def __call__(self):
         return self.__get_uuid()
 
+    def __del__(self):
+
+        if self.has_control_session() and self.has_terminal_session():
+            self.get_control_session().dissociate(self.get_terminal_session())
+
+        if self.has_control_session():
+            if self.keep_controlsession_alive:
+                # regenerate this session instance for re-usage if this is the last session for a certain session profile
+                # and keep_controlsession_alive is set to True...
+                self.virgin = True
+                self.connected = self.is_connected()
+                self.running = None
+                self.suspended = None
+                self.terminated = None
+                self._current_status = {
+                    'virgin': self.virgin,
+                    'connected': self.connected,
+                    'running': self.running,
+                    'suspended': self.suspended,
+                    'terminated': self.terminated,
+                }
+                self._last_status = None
+                self.session_name = None
+
+            else:
+                self.get_control_session().__del__()
+                self.control_session = None
+
+        if self.has_terminal_session():
+            self.get_terminal_session().__del__()
+            self.terminal_session = None
+
     def get_uuid(self):
         """\
         STILL UNDOCUMENTED
@@ -210,19 +259,39 @@ class X2goSession(object):
         return self.control_session._session_password
     __get_password = get_password
 
-    def get_server(self):
+    def get_server_peername(self):
         """\
         After a session has been setup up you can query the
         hostname of the host the sessions is connected to (or
         about to connect to).
 
-        @return: the hostname of the server the X2go session is
+        @return: the address of the server the X2go session is
             connected to (as an C{(addr,port)} tuple)
-        @rtype: tuple
+        @rtype: C{tuple}
 
         """
         return self.control_session.get_transport().getpeername()
-    __get_server = get_server
+    __get_server_peername = get_server_peername
+
+    def get_server_hostname(self):
+        """\
+        @return: the hostname of the server the X2go session is
+            connected to
+        @rtype: C{str}
+
+        """
+        return self.control_session.hostname
+    __get_server_hostname = get_server_hostname
+
+    def get_server_port(self):
+        """\
+        @return: the server-side TCP port that is used by the X2go session to 
+            connect the session
+        @rtype: C{str}
+
+        """
+        return self.control_session.port
+    __get_server_port = get_server_port
 
     def get_session_name(self):
         """\
@@ -233,8 +302,7 @@ class X2goSession(object):
         @rtype: C{str}
 
         """
-        if self.terminal_session is not None:
-            return self.terminal_session.get_session_name() or None
+        return self.session_name
     __get_session_name = get_session_name
 
     def get_session_cmd(self):
@@ -255,6 +323,14 @@ class X2goSession(object):
         return self.control_session
     __get_control_session = get_control_session
 
+    def has_control_session(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.control_session is not None
+    __has_control_session = has_control_session
+
     def get_terminal_session(self):
         """\
         STILL UNDOCUMENTED
@@ -314,11 +390,11 @@ class X2goSession(object):
         STILL UNDOCUMENTED
 
         """
-        self.connected = False
-        self.running = False
-        self.suspended = False
-        self.terminated = False
         self.control_session.disconnect()
+        self.connected = False
+        self.running = None
+        self.suspended = None
+        self.terminated = None
     __disconnect = disconnect
 
     def set_print_action(self, print_action, **kwargs):
@@ -332,13 +408,21 @@ class X2goSession(object):
     __set_print_action = set_print_action
 
     def is_alive(self):
-        _alive = self.control_session.is_alive()
-        if not _alive:
-            self.disconnect()
-        return _alive
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        self.connected = self.control_session.is_alive()
+        if not self.connected:
+            self._X2goSession__disconnect()
+        return self.connected
     __is_alive = is_alive
 
     def clean_sessions(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
         if self.is_alive():
             self.control_session.clean_sessions()
         else:
@@ -346,11 +430,53 @@ class X2goSession(object):
     __clean_sessions = clean_sessions
 
     def list_sessions(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
         if not self.is_alive():
             self._X2goSession__disconnect()
         return self.control_session.list_sessions()
     __list_sessions = list_sessions
 
+    def update_status(self, session_list=None):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        self._last_status = copy.deepcopy(self._current_status)
+        if session_list is None:
+            try:
+                session_list = self.control_session.list_sessions()
+                self.connected = True
+            except X2goControlSessionException:
+                self.connected = False
+                self.running = None
+                self.suspended = None
+                self.terminated = None
+        try:
+            _session_info = session_list[self.get_session_name()]
+            self.running = _session_info.is_running()
+            self.suspended = _session_info.is_suspended()
+            if not self.virgin:
+                self.terminated = not (_session_info.is_running() or _session_info.is_suspended())
+            else:
+                self.terminated = None
+        except KeyError:
+            self.running = False
+            self.suspended = False
+            if not self.virgin:
+                self.terminated = True
+
+        self._current_status = {
+            'virgin': self.virgin,
+            'connected': self.connected,
+            'running': self.running,
+            'suspended': self.suspended,
+            'terminated': self.terminated,
+        }
+    __update_status = update_status
+
     def resume(self, session_name=None):
         """\
         Resume or continue a suspended / running X2go session on the
@@ -360,11 +486,22 @@ class X2goSession(object):
         @type session_name: C{str}
 
         """
+        _new_session = False
+        if self.session_name is None:
+            self.session_name = session_name
+
         if self.is_alive():
             _control = self.control_session
-            _terminal = _control.resume(session_name=session_name, 
+            _terminal = _control.resume(session_name=self.session_name, 
                                         logger=self.logger, **self.terminal_params)
             self.terminal_session = _terminal
+
+            if self.session_name is None:
+                _new_session = True
+                self.session_name = self.terminal_session.session_info.name
+
+            print 'STARTING SESSION: %s'  % self.session_name
+
             if _terminal is not None:
 
                 if SUPPORTED_SOUND and _terminal.params.snd_system is not 'none':
@@ -385,9 +522,10 @@ class X2goSession(object):
                             _terminal.share_local_folder(_folder)
 
                 # only run the session startup command if we do not resume...
-                if session_name is None:
-                    _terminal.run_command()
+                if _new_session:
+                    self.terminal_session.run_command()
 
+                self.virgin = False
                 self.suspended = False
                 self.running = True
                 self.terminated = False
@@ -404,6 +542,7 @@ class X2goSession(object):
         Start a new X2go session on the remote X2go server.
 
         """
+        self.session_name = None
         self.resume()
     __start = start
 
@@ -420,11 +559,27 @@ class X2goSession(object):
 
         """
         if self.is_alive():
-            if self.terminal_session.suspend():
+            if self.has_terminal_session():
+                if self.terminal_session.suspend():
+
+                    self.running = False
+                    self.suspended = True
+                    self.terminated = False
+                    self.session_cleanup()
+                    return True
+
+            elif self.has_control_session() and self.session_name:
+                if self.control_session.suspend(session_name=self.session_name):
+
+                    self.running = False
+                    self.suspended = True
+                    self.terminated = False
+                    self.session_cleanup()
+                    return True
+
+            else:
+                raise X2goClientException('cannot suspend session')
 
-                self.running = False
-                self.suspended = True
-                return True
         else:
             self._X2goSession__disconnect()
         return False
@@ -443,12 +598,26 @@ class X2goSession(object):
 
         """
         if self.is_alive():
-            if self.terminal_session.terminate():
+            if self.has_terminal_session():
+                if self.terminal_session.terminate():
+
+                    self.running = False
+                    self.suspended = False
+                    self.terminated = True
+                    self.session_cleanup()
+                    return True
+
+            elif self.has_control_session() and self.session_name:
+                if self.control_session.terminate(session_name=self.session_name):
+
+                    self.running = False
+                    self.suspended = False
+                    self.terminated = True
+                    self.session_cleanup()
+                    return True
+            else:
+                raise X2goClientException('cannot terminate session')
 
-                self.running = False
-                self.suspended = False
-                self.terminated = True
-                return True
         else:
             self._X2goSession__disconnect()
 
@@ -495,7 +664,6 @@ class X2goSession(object):
         return False
     __session_ok = session_ok
 
-
     def is_connected(self):
         """\
         Test if this registered X2go session is connected to the 
@@ -505,7 +673,12 @@ class X2goSession(object):
         @rtype: C{bool}
 
         """
-        return self.control_session.is_connected()
+        self.connected = self.control_session.is_connected()
+        if not self.connected:
+            self.running = None
+            self.suspended = None
+            self.terminated = None
+        return self.connected
     __is_connected = is_connected
 
     def is_running(self):
@@ -516,7 +689,14 @@ class X2goSession(object):
         @rtype: C{bool}
 
         """
-        return self.is_connected() and self.control_session.is_running(self.get_session_name())
+        if self.is_connected():
+            self.running = self.control_session.is_running(self.get_session_name())
+            if self.running:
+                self.suspended = False
+                self.terminated = False
+            if self.virgin and not self.running:
+                self.running = None
+        return self.running
     __is_running = is_running
 
     def is_suspended(self):
@@ -527,7 +707,14 @@ class X2goSession(object):
         @rtype: C{bool}
 
         """
-        return self.is_connected() and self.control_session.is_suspended(self.get_session_name())
+        if self.is_connected():
+            self.suspended = self.control_session.is_suspended(self.get_session_name())
+            if self.suspended:
+                self.running = False
+                self.terminated = False
+            if self.virgin and not self.suspended:
+                self.suspended = None
+        return self.suspended
     __is_suspended = is_suspended
 
     def has_terminated(self):
@@ -538,7 +725,14 @@ class X2goSession(object):
         @rtype: C{bool}
 
         """
-        return self.is_connected() and self.control_session.has_terminated(self.get_session_name())
+        if self.is_connected():
+            self.terminated = not self.virgin and self.control_session.has_terminated(self.get_session_name())
+            if self.terminated:
+                self.running = False
+                self.suspended = False
+            if self.virgin and not self.terminated:
+                self.terminated = None
+        return self.has_terminated
     __has_terminated = has_terminated
 
     def share_local_folder(self, folder_name):
@@ -557,4 +751,10 @@ class X2goSession(object):
         return self.terminal_session.share_local_folder(folder_name=folder_name)
     __share_local_folder = share_local_folder
 
+    def session_cleanup(self):
+        """\
+        STILL UNDOCUMENTED
 
+        """
+        if self.has_terminal_session():
+            self.terminal_session.release_proxy()
diff --git a/x2go/utils.py b/x2go/utils.py
index 8a2fa06..2fc705b 100644
--- a/x2go/utils.py
+++ b/x2go/utils.py
@@ -32,6 +32,7 @@ import paramiko
 
 # Python X2go modules
 from defaults import _pack_methods_nx3
+from defaults import X2GO_SESSIONPROFILE_DEFAULTS
 
 
 def is_in_nx3packmethods(method):
@@ -109,6 +110,12 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
 
         _params = copy.deepcopy(_options)
 
+        # get rid of unknown session profile options
+        _known_options = X2GO_SESSIONPROFILE_DEFAULTS.keys()
+        for p in _params.keys():
+            if p not in _known_options:
+                del _params[p]
+
         _rename_dict = {
             'host': 'server',
             'user': 'username',
@@ -188,7 +195,7 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
             _params['session_type'] = 'desktop'
         del _params['rootless']
 
-        # currently ignored in Python X2go, use it for client implementations
+        # currently known but ignored in Python X2go
         _ignored_options = [
             'iconvto',
             'iconvfrom',
@@ -203,9 +210,12 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
             'icon',
             'applications',
             'xdmcpserver',
+            'usesshproxy',
+            'sshproxy',
         ]
         for i in _ignored_options:
             del _params[i]
+
         return _params
 
 def session_names_by_timestamp(session_infos):
diff --git a/x2go/x2go_exceptions.py b/x2go/x2go_exceptions.py
index 2eef4e5..e969875 100644
--- a/x2go/x2go_exceptions.py
+++ b/x2go/x2go_exceptions.py
@@ -39,11 +39,13 @@ SSHException = paramiko.SSHException
 
 class _X2goException(exceptions.BaseException): pass
 class X2goClientException(_X2goException): pass
+class X2goSessionException(_X2goException): pass
 class X2goControlSessionException(_X2goException): pass
 class X2goTerminalSessionException(_X2goException): pass
 class X2goSessionCacheException(_X2goException): pass
 class X2goUserException(_X2goException): pass
 class X2goProfileException(_X2goException): pass
+class X2goSessionRegistryException(_X2goException): pass
 class X2goSettingsException(_X2goException): pass
 class X2goFwTunnelException(_X2goException): pass
 class X2goRevFwTunnelException(_X2goException): pass


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