[X2Go-Commits] python-x2go.git - twofactorauth (branch) updated: c4b70151df3b4f2572f1d9dc1699f29b072016b7

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


The branch, twofactorauth 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