[X2Go-Commits] python-x2go.git - build-baikal (branch) updated: ce981684654d333b61219c0b76e625d7c38561f2

X2Go dev team git-admin at x2go.org
Wed Jan 8 15:27:13 CET 2014


The branch, build-baikal has been updated
       via  ce981684654d333b61219c0b76e625d7c38561f2 (commit)
      from  62cdc5c76c212bbbf0086717f56d147107f0f8d1 (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/__init__.py                           |    2 +-
 x2go/client.py                             |  437 +++++++++++++++-----------
 x2go/defaults.py                           |  108 +++++--
 x2go/forward.py                            |    5 +-
 x2go/guardian.py                           |    5 +
 x2go/log.py                                |   18 +-
 x2go/printing.py                           |   88 +++---
 x2go/profiles.py                           |  469 +++++++---------------------
 x2go/proxy.py                              |    9 +-
 x2go/rforward.py                           |   19 +-
 x2go/session.py                            |   69 ++--
 x2go/settings.py                           |   27 +-
 x2go/sftpserver.py                         |   40 ++-
 x2go/utils.py                              |  156 ++++++++-
 x2go/{exceptions.py => x2go_exceptions.py} |    4 +-
 15 files changed, 757 insertions(+), 699 deletions(-)
 rename x2go/{exceptions.py => x2go_exceptions.py} (96%)

The diff of changes is:
diff --git a/x2go/__init__.py b/x2go/__init__.py
index 2a06dff..ebf297a 100644
--- a/x2go/__init__.py
+++ b/x2go/__init__.py
@@ -47,7 +47,7 @@ _signal.signal (_signal.SIGTERM, guardian._sigterm_handle )
 _signal.signal (_signal.SIGINT, guardian._sigterm_handle )
 
 from client import X2goClient
-from exceptions import *
+from x2go_exceptions import *
 from log import *
 
 from cleanup import x2go_cleanup
diff --git a/x2go/client.py b/x2go/client.py
index 2d1a50c..4e97fa5 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -23,6 +23,7 @@ X2goClient class - use this class in your Python-based X2go applications.
 
 The X2goClient class supports registry based multiple sessions, parsing of
 configuration files and managing X2go session profiles.
+
 """
 __NAME__ = 'x2goclient-pylib'
 
@@ -33,7 +34,8 @@ import copy
 # Python X2go modules
 from settings import X2goClientSettings
 from printing import X2goClientPrinting
-#from profiles import X2goClientSessionProfile, X2goClientSessionProfiles
+from profiles import X2goClientSessions
+from registry import X2goSessionRegistry
 from session import X2goSession, _X2GO_SESSION_OPTIONS
 import log
 
@@ -67,20 +69,20 @@ class X2goClient(object):
         - register a new X2goClient session, this creates an X2goSession instance
           and calls its constructor method::
 
-            x2go_session_hash = x2go_client.register_session(<many-options>)
+            x2go_profile_id = x2go_client.register_session(<many-options>)
 
         - connect to the session's remote X2go server (SSH/Paramiko)::
 
-            x2go_client.connect_session(x2go_session_hash)
+            x2go_client.connect_session(x2go_profile_id)
 
         - with the connected X2go client session you can start or resume a remote 
           X-windows session on an X2go server now::
 
-            x2go_client.start_session(x2go_session_hash)
+            x2go_client.start_session(x2go_profile_id)
 
           resp.::
 
-            x2go_client.start_session(x2go_session_hash, session_name=<session_name_of_resumable_session>)
+            x2go_client.start_session(x2go_profile_id, session_name=<session_name_of_resumable_session>)
 
     A new config based (i.e. using pre-defined session profiles) X2go session in an X2goClient instance 
     is initiated in a slightly different way:
@@ -89,13 +91,14 @@ class X2goClient(object):
 
     You can suspend or terminate your sessions by calling the follwing commands::
 
-        x2go_client.suspend_session(x2go_session_hash)
+        x2go_client.suspend_session(x2go_profile_id)
 
     resp.::
 
-        x2go_client.terminate_session(x2go_session_hash)
+        x2go_client.terminate_session(x2go_profile_id)
+
     """
-    session_registry = {}
+    session_registry = None
 
     def __init__(self, loglevel=log.loglevel_DEFAULT, logger=None, *args, **kwargs):
         """\
@@ -105,18 +108,52 @@ class X2goClient(object):
         @param loglevel: if no X2goLogger object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: int
+
         """
-        self.settings_config = X2goClientSettings()
-        #self.sessions_config = X2goClientSessionProfiles()
-        self.printing_config = X2goClientPrinting()
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
         else:
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
+        self.session_registry = X2goSessionRegistry()
+
+    def get_username(self, profile_id):
+        """\
+        After a session has been setup up you can query the 
+        username the sessions runs as.
+
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
+
+        @return: the remote username the X2go session runs as
+        @rtype: str
+
+        """
+        return self.session_registry(profile_id).session_object.get_transport().get_username()
 
-    def register_session(self, server=None, profile_name='UNKNOWN', printing=False, **kwargs):
+    def get_server(self, profile_id):
+        """\
+        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).
+
+        @param profile_id: the X2go sessions UUID registry hash
+        @type profile_id: str
+
+        @return: the host an X2go session is connected to 
+            (as an C{(addr,port)} tuple) 
+        @rtype: tuple
+
+        """
+        return self.session_registry(profile_id).session_object.get_transport().getpeername()
+
+    ###
+    ### SESSION ORIENTED CODE
+    ###
+
+    def register_session(self, server=None, profile_id=None, profile_name=None, custom_profile_name=None, 
+                         printing=False, share_local_folders=[], **kwargs):
         """\
         Register a new X2go client session. Within one X2goClient 
         instance you can manage several sessions on serveral
@@ -139,131 +176,82 @@ class X2goClient(object):
 
         @return: a unique identifier (UUID) for the newly registered X2go session
         @rtype: str
+
         """
-        if server is None and profile_name is 'UNKNOWN':
-            return None
+        if profile_id and self.session_registry.has_profile_id(profile_id):
+            _p = profile_id
+        elif profile_name and self.session_registry.has_profile_name(profile_name):
+            _p = profile_name
+        else:
+            _p = None
+
+        if _p:
+            kwargs = self.session_registry.get_session_params(_p)
+            profile_id = self.session_registry(_p).profile_id
+        else:
+            if server is None:
+                return None
+            _profile_name = profile_name or custom_profile_name or sys.args[0]
+            kwargs['server'] = server
+            kwargs['printing'] = printing
+            kwargs['share_local_folders'] = share_local_folders
 
-        # differentiate SSH options from X2go options
-        x2go_session_options = copy.deepcopy(kwargs)
-        paramiko_connect_options = copy.deepcopy(kwargs)
+            profile_id = self.session_registry.register_by_session_params(_profile_name, **kwargs)
 
-        for k in kwargs.keys():
-            if k in _X2GO_SESSION_OPTIONS:
-                del paramiko_connect_options[k]
-            else:
-                del x2go_session_options[k]
+        connect_options = self.session_registry(profile_id).connect_options
+        session_options = self.session_registry(profile_id).session_options
 
         self.logger('initializing X2go session...', log.loglevel_NOTICE)
 
         self.logger('X2go session options are:', log.loglevel_DEBUG)
-        for k in x2go_session_options:
-            self.logger('    %s: %s' % (k,x2go_session_options[k]), log.loglevel_DEBUG)
+        for k in session_options:
+            self.logger('    %s: %s' % (k, session_options[k]), log.loglevel_DEBUG)
 
         self.logger('Paramiko connect options are:', log.loglevel_DEBUG)
-        for k in paramiko_connect_options:
-            self.logger('    %s: %s' % (k,paramiko_connect_options[k]), log.loglevel_DEBUG)
+        for k in connect_options:
+            self.logger('    %s: %s' % (k,connect_options[k]), log.loglevel_DEBUG)
 
         # setup X2go session
-        session = X2goSession(logger=self.logger, **x2go_session_options)
-        session_hash = uuid.uuid1()
-        self.session_registry[session_hash] = {
-            'session': session,
-            'connected': False,
-            'running': False,
-            'resumed': False,
-            'suspended': False,
-            'terminated': False,
-            'server': server,
-            'printing': printing,
-            'paramiko_connect_options': paramiko_connect_options,
-            'x2go_session_options': x2go_session_options,
-            'profile_name': profile_name,
-            #'profile': X2goClientSessionProfile(**kwargs)
-        }
-        return session_hash
-
-
-    def get_username(self, session_hash):
-        """\
-        After a session has been setup up you can query the 
-        username the sessions runs as.
-
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
-
-        @return: the remote username the X2go session runs as
-        @rtype: str
-        """
-        return self.session_registry[session_hash]['session'].get_transport().get_username()
-
-
-    def get_server(self, session_hash):
-        """\
-        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).
-
-        @param session_hash: the X2go sessions UUID registry hash
-        @type session_hash: str
-
-        @return: the host an X2go session is connected to 
-            (as an C{(addr,port)} tuple) 
-        @rtype: tuple
-        """
-        return self.session_registry[session_hash]['session'].get_transport().getpeername()
-
+        session = X2goSession(logger=self.logger, **session_options)
+        return self.session_registry(profile_id).uuid
 
-    def get_session(self, session_hash):
+    def get_session(self, profile_id):
         """\
         Retrieve the complete X2goSession object that has been 
         registry under the given sesion registry hash.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
 
         @return: the L{X2goSession} object
         @rtype: obj
-        """
-        return self.session_registry[session_hash]['session']
-    with_session = get_session
-
 
-    def get_profile_name(self, session_hash):
-        """\
-        Retrieve the profile name of the session that has been registered
-        under C{session_hash}
-
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
-
-        @return: X2go client profile name of the session
-        @rtype: str
         """
-        return self.session_registry[session_hash]['profile_name']
-
+        return self.session_registry(profile_id).session_object
+    with_session = get_session
 
-    def get_session_name(self, session_hash):
+    def get_session_name(self, profile_id):
         """\
         Retrieve the server-side X2go session name for the session that has
-        been registered under C{session_hash}.
+        been registered under C{profile_id}.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
 
         @return: X2go session name
         @rtype: str
-        """
-        return self.session_registry[session_hash]['session'].session_info
 
+        """
+        return self.session_registry(profile_id).session_object.session_info
 
-    def __connect_session(self, session_hash, password=None, add_to_known_hosts=False, force_password_auth=False):
+    def __connect_session(self, profile_id, password=None, add_to_known_hosts=False, force_password_auth=False):
         """\
-        Connect to a registered X2go session with registry hash C{<session_hash>}. 
+        Connect to a registered X2go session with registry hash C{<profile_id>}. 
         This method basically wraps around paramiko.SSHClient.connect() for the 
         corresponding session.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
         @param password: the user's password for the X2go server that is going to be 
             connected to
         @type password: str
@@ -274,34 +262,36 @@ class X2goClient(object):
         @param force_password_auth: disable SSH pub/priv key authentication mechanisms
             completely
         @type force_password_auth: bool
+
         """
-        session = self.session_registry[session_hash]['session']
-        server = self.session_registry[session_hash]['server']
-        paramiko_connect_options = self.session_registry[session_hash]['paramiko_connect_options']
-        paramiko_connect_options['password'] = password
-        paramiko_connect_options['force_password_auth'] = force_password_auth
-        session.connect(server, **paramiko_connect_options)
-        self.session_registry[session_hash]['connected'] = True
+        session = self.session_registry(profile_id).session_object
+        server = self.session_registry(profile_id).server
+        connect_options = self.session_registry(profile_id).connect_options
+        connect_options['password'] = password
+        connect_options['force_password_auth'] = force_password_auth
+        session.connect(server, **connect_options)
+        self.session_registry(profile_id).connected = True
     connect_session = __connect_session
 
-
-    def session_print_action(self, session_hash, print_action, **kwargs):
+    def __session_print_action(self, profile_id, print_action, **kwargs):
         """\
         STILL UNDOCUMENTED
+
         """
         if type(print_action) is not types.StringType:
             return False
-        self.with_session(session_hash).set_print_action(print_action, **kwargs)
-
+        self.with_session(profile_id).set_print_action(print_action, **kwargs)
+    session_print_action = __session_print_action
 
-    def __start_session(self, session_hash):
+    def __start_session(self, profile_id):
         """\
         Start a new X2go session on the remote X2go server.
 
-        @param session_hash: the X2go sessions UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go sessions UUID registry hash
+        @type profile_id: str
+
         """
-        session = self.session_registry[session_hash]['session']
+        session = self.session_registry(profile_id).session_object
 
         session.start()
 
@@ -309,54 +299,59 @@ class X2goClient(object):
             session.start_sound()
 
         session.start_sshfs()
-        if self.session_registry[session_hash]['printing']:
+        if self.session_registry(profile_id).printing:
             session.start_printing()
 
+        if self.session_registry(profile_id).share_local_folders:
+            if session.get_transport().reverse_tunnels['sshfs'][1] is not None:
+                for _folder in self.session_registry(profile_id).share_local_folders:
+                    session.share_local_folder(_folder)
+
         session.run_command()
-        self.session_registry[session_hash]['running'] = True
+        self.session_registry(profile_id).running = True
     start_session = __start_session
 
-
-    def __clean_sessions(self, session_hash):
+    def __clean_sessions(self, profile_id):
         """\
         Find running X2go sessions that have been standard by the connected
         user and terminate them.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
+
         """
-        session = self.session_registry[session_hash]['session']
+        session = self.session_registry(profile_id).session_object
         session_infos = session.list_sessions()
         for session_info in session_infos.values():
             session.terminate(session_name=session_info)
     clean_sessions = __clean_sessions
 
-
-    def __list_sessions(self, session_hash):
+    def __list_sessions(self, profile_id):
         """\
-        Use the X2go session registered under C{session_hash} to
+        Use the X2go session registered under C{profile_id} to
         retrieve a list of running or suspended X2go sessions on the 
         connected X2go server (for the authenticated user).
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
+
         """
-        session = self.session_registry[session_hash]['session']
+        session = self.session_registry(profile_id).session_object
         return session.list_sessions()
     list_sessions = __list_sessions
 
-
-    def __resume_session(self, session_hash, session_name):
+    def __resume_session(self, profile_id, session_name):
         """\
         Resume or continue a suspended / running X2go session on the 
         remote X2go server.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
         @param session_name: the server-side name of an X2go session
         @type session_name: str
+
         """
-        session = self.session_registry[session_hash]['session']
+        session = self.session_registry(profile_id).session_object
         session.associate(session_name)
         session.resume()
 
@@ -364,14 +359,13 @@ class X2goClient(object):
             session.start_sound()
 
         session.start_sshfs()
-        if self.session_registry[session_hash]['printing']:
+        if self.session_registry(profile_id).printing:
             session.start_printing()
 
-        self.session_registry[session_hash]['running'] = True
+        self.session_registry(profile_id).running = True
     resume_session = __resume_session
 
-
-    def __suspend_session(self, session_hash, session_name=None):
+    def __suspend_session(self, profile_id, session_name=None):
         """\
         Suspend an X2go session. 
 
@@ -382,22 +376,22 @@ class X2goClient(object):
         registering an X2go server session and then passing the 
         server-side X2go session name to this method.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
         @param session_name: the server-side name of an X2go session
         @type session_name: str
+
         """
-        session = self.session_registry[session_hash]['session']
+        session = self.session_registry(profile_id).session_object
         if session_name:
             session.associate(session_name)
         session.suspend(session_name=session_name)
         if session_name is None:
-            self.session_registry[session_hash]['running'] = False
-            self.session_registry[session_hash]['suspended'] = True
+            self.session_registry(profile_id).running = False
+            self.session_registry(profile_id).suspended = True
     suspend_session = __suspend_session
 
-
-    def __terminate_session(self, session_hash, session_name=None):
+    def __terminate_session(self, profile_id, session_name=None):
         """\
         Terminate an X2go session. 
 
@@ -408,95 +402,174 @@ class X2goClient(object):
         registering an X2go server session and then passing the 
         server-side X2go session name to this method.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
         @param session_name: the server-side name of an X2go session
         @type session_name: str
+
         """
-        session = self.session_registry[session_hash]['session']
+        session = self.session_registry(profile_id).session_object
         if session_name:
             session.associate(session_name=session_name)
         session.terminate()
         if session_name is None:
-            self.session_registry[session_hash]['running'] = False
-            self.session_registry[session_hash]['suspended'] = False
-            self.session_registry[session_hash]['terminated'] = True
+            self.session_registry(profile_id).running = False
+            self.session_registry(profile_id).suspended = False
+            self.session_registry(profile_id).terminated = True
     terminate_session = __terminate_session
 
+    ###
+    ### PROFILE ORIENTED CODE
+    ###
 
-    def __session_ok(self, session_hash):
+    def __load_session_profiles(self):
         """\
-        Test if the X2go session registered as C{session_hash} is
-        in a healthy state.
+        STILL UNDOCUMENTED
+
+
+        """
+        self.session_registry.read_session_profiles()
+    load_session_profiles = __load_session_profiles
+
+#    def new_session_profile(self, profile_name='NEW_SESSION_PROFILE', **kwargs):
+#        """\
+#        STILL UNDOCUMENTED
+#
+#        @param profile_name: name of a session profile to load from your session
+#            config
+#        @type profile_name: str
+#
+#        @return: a unique identifier (UUID) for the newly registered X2go session
+#        @rtype: str
+#
+#        """
+#        profile = self.session_profiles.new_profile(profile_name=profile_name, **kwargs)
+#        return self.register_profile(profile)
+#
+#    def get_session_profile(self, session_hash):
+#        """\
+#        Retrieve the complete X2goSession object that has been 
+#        registry under the given sesion registry hash.
+#
+#        @param session_hash: the X2go session's UUID registry hash
+#        @type session_hash: str
+#
+#        @return: the L{X2goSession} object
+#        @rtype: obj
+#
+#        """
+#        return self.session_registry[session_hash]['profile']
+#    with_profile = get_session_profile
+#
+    def get_session_profile_name(self, profile_id):
+        """\
+        Retrieve the profile name of the session that has been registered
+        under C{session_hash}
+
 
         @param session_hash: the X2go session's UUID registry hash
         @type session_hash: str
 
+        @return: X2go client profile name of the session
+        @rtype: str
+
+        """
+        return self.session_registry(profile_id).profile_name
+    get_profile_name = get_session_profile_name
+
+    def get_session_profile_id(self, profile_name):
+        """\
+        Retrieve the session profile id of the session whose profile name
+        is C{profile_name}
+
+        @param profile_name: the session profile name
+        @type profile_name: str
+
+        @return: the session profile's id
+        @rtype: str
+
+        """
+        return self.session_registry(profile_name).profile_id
+    get_profile_id = get_session_profile_id
+
+    ###
+    ### QUERYING INFORMATION
+    ###
+
+    def __session_ok(self, profile_id):
+        """\                                     
+        Test if the X2go session registered as C{profile_id} is
+        in a healthy state.
+
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
+
         @return: C{True} if session is ok, C{False} otherwise
         @rtype: bool
+
         """
-        return self.with_session(session_hash).ok()
+        return self.with_session(profile_id).ok()
     session_ok = __session_ok
 
-
-    def __is_running(self, session_hash):
+    def __is_running(self, profile_id):
         """\
-        Test if the X2go session registered as C{session_hash} is up 
+        Test if the X2go session registered as C{profile_id} is up 
         and running.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
 
         @return: C{True} if session is running, C{False} otherwise
         @rtype: bool
+
         """
-        return self.with_session(session_hash).is_running()
+        return self.with_session(profile_id).is_running()
     is_running = __is_running
 
-
-    def __is_suspended(self, session_hash):
+    def __is_suspended(self, profile_id):
         """\
-        Test if the X2go session registered as C{session_hash} 
+        Test if the X2go session registered as C{profile_id} 
         is in suspended state.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
 
         @return: C{True} if session is suspended, C{False} otherwise
         @rtype: bool
+
         """
-        return self.with_session(session_hash).is_suspended()
+        return self.with_session(profile_id).is_suspended()
     is_suspended = __is_suspended
 
-
-    def __has_terminated(self, session_hash):
+    def __has_terminated(self, profile_id):
         """\
-        Test if the X2go session registered as C{session_hash} 
+        Test if the X2go session registered as C{profile_id} 
         has terminated.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
 
         @return: C{True} if session has terminated, C{False} otherwise
         @rtype: bool
+
         """
-        return self.with_session(session_hash).has_terminated()
+        return self.with_session(profile_id).has_terminated()
     has_terminated = __has_terminated
 
-
-    def __share_local_folder(self, session_hash, folder_name):
+    def __share_local_folder(self, profile_id, folder_name):
         """\
-        Share a local folder with the X2go session registered as C{session_hash}.
+        Share a local folder with the X2go session registered as C{profile_id}.
 
-        @param session_hash: the X2go session's UUID registry hash
-        @type session_hash: str
+        @param profile_id: the X2go session's UUID registry hash
+        @type profile_id: str
         @param folder_name: the full path to an existing folder on the local 
             file system
         @type folder_name: str
 
         @return: returns C{True} if the local folder has been successfully mounted within the 
-            X2go server session registerd as UUID C{session_hash}
+            X2go server session registerd as UUID C{profile_id}
         @rtype: bool
+
         """
-        return self.with_session(session_hash).share_local_folder(folder_name=folder_name)
+        return self.with_session(profile_id).share_local_folder(folder_name=folder_name)
     share_local_folder = __share_local_folder
diff --git a/x2go/defaults.py b/x2go/defaults.py
index be88ec0..60a91e0 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
@@ -45,41 +45,88 @@ X2GO_CLIENT_ROOTDIR = '.x2goclient'
 ## X2go Printing
 ##
 
+X2GO_SETTINGS_CONFIGFILES = [
+    '/etc/x2goclient/settings',
+    os.path.join(LOCAL_HOME, X2GO_CLIENT_ROOTDIR, 'settings'),
+]
 X2GO_PRINTING_CONFIGFILES = [
     '/etc/x2goclient/printing',
     os.path.join(LOCAL_HOME, X2GO_CLIENT_ROOTDIR, 'printing'),
 ]
+X2GO_SESSIONPROFILES_CONFIGFILES = [
+    '/etc/x2goclient/sessions',
+    os.path.join(LOCAL_HOME, X2GO_CLIENT_ROOTDIR, 'sessions'),
+]
 
-X2GO_PRINTING_CONFIG = """\
-[General]
-# ignored in Python X2go
-showdialog=false
-# if true, open a PDF viewer (or save as PDF file). If false, print via CUPS or print command
-pdfview=true
-[print]
-# If false, print via CUPS. If true, run "command" to process the print job
-startcmd=false
-# print command for non-CUPS printing
-command=lpr
-# ignored in Python X2go
-stdin=false
-# ignored in Python X2go
-ps=false
-
-[view]
-# If General->pdfview is true: 
-#   if open is true, the PDF viewer command is executed
-#   if open is false, the incoming print job is saved in ~/PDF folder 
-open=true
-# command to execute as PDF viewer
-command=xpdf
-
-[CUPS]
-# default print queue for CUPS, if print queue does not exist, the default 
-# CUPS queue is detected
-defaultprinter=PDF
-"""
-
+X2GO_CLIENTSETTINGS_DEFAULTS = {
+    'LDAP': {
+        'useldap': False,
+        'port': 389,
+        'server': 'localhost',
+        'port1': 0,
+        'port2': 0,
+        },
+    'General': {
+        # clientport is not needed for Python X2go
+        'clientport': 22, 
+        'autoresume': True,
+        },
+    'Authorization': {
+        'newprofile': True,
+        'suspend': True,
+        'editprofile': True,
+        'resume': True
+        },
+    }
+X2GO_CLIENTPRINTING_DEFAULTS = {
+    'General': {
+        # ignored in Python X2go
+        'showdialog': False,
+        # if true, open a PDF viewer (or save as PDF file). If false, print via CUPS or print command
+        'pdfview': True,
+        },
+    'print': {
+        # If false, print via CUPS. If true, run "command" to process the print job
+        'startcmd': False,
+        # print command for non-CUPS printing
+        'command': 'lpr',
+        # ignored in Python X2go
+        'stdin': False,
+        # ignored in Python X2go
+        'ps': False,
+        },
+    'view': {
+        # If General->pdfview is true: 
+        #   if open is true, the PDF viewer command is executed
+        #   if open is false, the incoming print job is saved in ~/PDF folder 
+        'open': True,
+        # command to execute as PDF viewer
+        'command': 'xpdf',
+        },
+    'CUPS': {
+        # default print queue for CUPS, if print queue does not exist, the default 
+        # CUPS queue is detected
+        'defaultprinter': 'PDF',
+        },
+    }
+X2GO_SESSIONPROFILE_DEFAULTS = {
+    'speed': 2, 'pack': '16m-jpeg', 'quality': 9, 'link':'ADSL',
+    'iconvto': 'UTF-8', 'iconvfrom': 'ISO-8859-15', 'useiconv': False,
+    '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, 
+    'printing':True, 
+    '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, 
+    'default':False,
+    'print': True,
+    'xdmcpserver': 'localhost',
+    }
 
 ##
 ## X2go Proxy defaults
@@ -171,3 +218,4 @@ X2GO_PRINT_ACTIONS = {
 DEFAULT_PDFVIEW_CMD = 'xdg-open'
 DEFAULT_PDFSAVE_LOCATION = '~/PDF'
 DEFAULT_PRINTCMD_CMD = 'lpr'
+
diff --git a/x2go/forward.py b/x2go/forward.py
index 7bde755..6fcc245 100644
--- a/x2go/forward.py
+++ b/x2go/forward.py
@@ -53,6 +53,7 @@ class X2goFwServer(StreamServer):
     @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
         constructed with the given loglevel
     @type loglevel: int
+
     """
     def __init__ (self, listener, remote_host, remote_port, ssh_transport, logger=None, loglevel=log.loglevel_DEFAULT,):
         if logger is None:
@@ -67,7 +68,6 @@ class X2goFwServer(StreamServer):
 
         StreamServer.__init__(self, listener, self.x2go_forward_tunnel_handle)
 
-
     def x2go_forward_tunnel_handle(self, fw_socket, address):
         """\
         Handle for SSH/Paramiko forwarding tunnel.
@@ -76,6 +76,7 @@ class X2goFwServer(StreamServer):
         @type fw_socket: class
         @param address: unused/ignored
         @type address: tuple
+
         """
         try:
             chan = self.ssh_transport.open_channel('direct-tcpip',
@@ -132,6 +133,7 @@ def start_forward_tunnel(local_port, remote_host, remote_port, ssh_transport, lo
     @param ssh_transport: the Paramiko/SSH transport (i.e. the X2go sessions SSH transport object)
     @param logger: an X2goLogger object
     @type logger: class
+
     """
     fw_server = X2goFwServer(('localhost', local_port), remote_host, remote_port, ssh_transport, logger=logger)
     try:
@@ -144,6 +146,7 @@ def start_forward_tunnel(local_port, remote_host, remote_port, ssh_transport, lo
 def stop_forward_tunnel(fw_server):
     """\
     Tear down a given Paramiko/SSH port forwarding tunnel.
+
     """
     fw_server.stop()
 
diff --git a/x2go/guardian.py b/x2go/guardian.py
index 7c97d52..4271aaf 100644
--- a/x2go/guardian.py
+++ b/x2go/guardian.py
@@ -45,12 +45,14 @@ class X2goSessionGuardian(threading.Thread):
     reverse forwarding tunnels, Paramiko transport threads, etc.). Their main function is 
     to tidy up once a session gets interrupted (SIGTERM, SIGINT). There is one  
     L{X2goSessionGuardian} for each L{X2goSession} instance.
+
     """
 
     active_threads = []
     """\
     List of active threads that this L{X2goSessionGuardian} instance will monitor. Whenever
     an L{X2goSession} starts a new sub-thread, it will be appended to this list.
+
     """
 
     def __init__(self, session, logger=None, loglevel=log.loglevel_DEFAULT):
@@ -62,6 +64,7 @@ class X2goSessionGuardian(threading.Thread):
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: int
+
         """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -77,6 +80,7 @@ class X2goSessionGuardian(threading.Thread):
     def guardian(self):
         """\
         The handler of this L{X2goSessionGuardian} thread.
+
         """
         global _sigterm_received
         while not _sigterm_received and self._keepalive:
@@ -88,6 +92,7 @@ class X2goSessionGuardian(threading.Thread):
     def stop_thread(self):
         """\
         Stop this L{X2goSessionGuardian} thread.
+
         """
         self._keepalive = False
 
diff --git a/x2go/log.py b/x2go/log.py
index a37c4c5..e7959d7 100644
--- a/x2go/log.py
+++ b/x2go/log.py
@@ -41,6 +41,7 @@ Default loglevel of X2goLogger objects is: NOTICE & WARN & ERROR
 class X2goLogger(object):
     """\
     A simple logger class, that is used by all Python X2go classes.
+
     """
     name = ''
     tag = ''
@@ -48,7 +49,6 @@ class X2goLogger(object):
     level = -1
     destination = sys.stderr
 
-
     _loglevel_NAMES = {8: 'error', 
                    16: 'warn', 
                    32: 'notice', 
@@ -57,8 +57,6 @@ class X2goLogger(object):
                    1024: 'debug-sftpxfer', 
                   }
 
-
-
     def __init__(self, name=sys.argv[0], tag=__NAME__, loglevel=loglevel_DEFAULT):
         """\
         @param name: name of the programme that uses Python X2go
@@ -67,13 +65,13 @@ class X2goLogger(object):
         @type tag: str
         @param loglevel: log level for Python X2go
         @type loglevel: int
+
         """
         self.name = os.path.basename(name)
         self.tag = tag
         self.loglevel = loglevel
         self.progpid = os.getpid()
 
-
     def message(self, msg, loglevel=loglevel_NONE):
         """\
         Log a message.
@@ -82,8 +80,8 @@ class X2goLogger(object):
         @type msg: str
         @param loglevel: log level of this message
         @type loglevel: int
-        """
 
+        """
         if loglevel & self.loglevel:
             self.destination.write('%s[%s] (%s) %s: %s\n' % (self.name, self.progpid, self.tag, self._loglevel_NAMES[loglevel].upper(), msg))
     __call__ = message
@@ -94,6 +92,7 @@ class X2goLogger(object):
 
         @param loglevel_name: name of loglevel to be set
         @type loglevel_name: str
+
         """
         if type(loglevel_name) is types.IntegerType:
             self.loglevel = loglevel_name
@@ -103,52 +102,59 @@ class X2goLogger(object):
         else:
             self.loglevel = loglevel_DEFAULT
 
-
     def set_loglevel_none(self):
         """\
         Silence logging completely.
+
         """
         self.loglevel = 0
 
     def set_loglevel_error(self):
         """\
         Set log level to I{ERROR}.
+
         """
         self.loglevel = loglevel_ERROR
 
     def set_loglevel_warn(self):
         """\
         Set log level to I{WARN}.
+
         """
         self.loglevel = loglevel_ERROR | loglevel_WARN
 
     def set_loglevel_notice(self):
         """\
         Set log level to I{NOTICE} (default).
+
         """
         self.loglevel = loglevel_ERROR | loglevel_WARN | loglevel_NOTICE
 
     def set_loglevel_info(self):
         """\
         Set log level to I{INFO}.
+
         """
         self.loglevel = loglevel_ERROR | loglevel_WARN | loglevel_NOTICE | loglevel_INFO
 
     def set_loglevel_debug(self):
         """\
         Set log level to I{DEBUG}.
+
         """
         self.loglevel = loglevel_ERROR | loglevel_WARN | loglevel_NOTICE | loglevel_INFO | loglevel_DEBUG
 
     def enable_debug_sftpxfer(self):
         """\
         Additionally, switch on sFTP data transfer debugging
+
         """
         self.loglevel = self.loglevel | loglevel_DEBUG_SFTPXFER
 
     def disable_debug_sftpxfer(self):
         """\
         Switch off sFTP data transfer debugging.
+
         """
         self.loglevel = self.loglevel ^ loglevel_DEBUG_SFTPXFER
 
diff --git a/x2go/printing.py b/x2go/printing.py
index 706228f..b39c960 100644
--- a/x2go/printing.py
+++ b/x2go/printing.py
@@ -28,6 +28,7 @@ print job.
 Print jobs can be either be sent to any of the local print queues, 
 be opened in an external PDF viewer, be saved to a local folder or be handed 
 over to a custom (print) command.
+
 """
 __NAME__ = 'x2goprint-pylib'
 
@@ -49,20 +50,22 @@ import log
 import defaults
 from defaults import LOCAL_HOME as _LOCAL_HOME
 from defaults import X2GO_CLIENT_ROOTDIR as _X2GO_CLIENT_ROOTDIR
+from defaults import X2GO_CLIENTPRINTING_DEFAULTS
 import utils
+import inifiles
 
 _PRINT_ENV = os.environ.copy()
 
-class X2goClientPrinting(inifiles.X2goProcessIniFile):
+class X2goClientPrinting(inifiles.X2goIniFile):
     """\
     STILL UNDOCUMENTED
+
     """
     config_files = []
     _print_action = None
+    defaultValues = defaults.X2GO_CLIENTPRINTING_DEFAULTS
 
-    optionxform = str
-
-    def __init__(self, config_files=defaults.X2GO_PRINTING_CONFIGFILES, logger=None, loglevel=log.loglevel_DEFAULT, config=None, *args, **kwargs):
+    def __init__(self, config_files=defaults.X2GO_PRINTING_CONFIGFILES, defaults=None, logger=None, loglevel=log.loglevel_DEFAULT):
         """\
         STILL UNDOCUMENTED
 
@@ -72,66 +75,44 @@ class X2goClientPrinting(inifiles.X2goProcessIniFile):
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: int
-        """
-        if logger is None:
-            self.logger = log.X2goLogger(loglevel=loglevel)
-        else:
-            self.logger = copy.deepcopy(logger)
-        self.logger.tag = __NAME__
-
-        ConfigParser.SafeConfigParser.__init__(self, *args, **kwargs)
 
-        if (config is not None) and type(config) is types.StringType:
-            c = cStringIO.StringIO(config)
-            self.readfp(c)
-        else:
-            if type(config_files) in (types.TupleType, types.ListType):
-                self.config_files = copy.deepcopy(config_files)
-            else:
-                self.config_files = []
-            self.read(self.config_files)
+        """
+        inifiles.X2goIniFile.__init__(self, config_files, defaults=defaults, logger=logger, loglevel=loglevel)
 
         self._detect_print_action()
 
 
     def _detect_print_action(self):
+        """\
+        STILL UNDOCUMENTED
 
-        _general_pdfview = ( self.get('General', 'pdfview').lower() == 'true' )
-        _view_open = ( self.get('view', 'open').lower() == 'true' )
-        _print_startcmd = ( self.get('print', 'startcmd').lower() == 'true' )
+        """
+        _general_pdfview = self.getValue('General', 'pdfview', key_type=types.BooleanType)
+        _view_open = self.getValue('view', 'open', key_type=types.BooleanType)
+        _print_startcmd = self.getValue('print', 'startcmd', key_type=types.BooleanType)
 
         if _general_pdfview and _view_open:
-            _view_command = self.get('view', 'command')
+            _view_command = self.getValue('view', 'command')
             self._print_action = X2goPrintActionPDFVIEW(pdf_viewer_command=_view_command, logger=self.logger)
 
         elif _general_pdfview and not _view_open:
             self._print_action = X2goPrintActionPDFSAVE(logger=self.logger)
 
         elif not _general_pdfview and not _print_startcmd:
-            _cups_defaultprinter = self.get('CUPS', 'defaultprinter')
+            _cups_defaultprinter = self.getValue('CUPS', 'defaultprinter')
             self._print_action = X2goPrintActionPRINT(default_printer=_cups_defaultprinter, logger=self.logger)
 
         elif not _general_pdfview and _print_startcmd:
-            _print_command = self.get('print', 'command')
+            _print_command = self.getValue('print', 'command')
             self._print_action = X2goPrintActionPRINTCMD(print_cmd=_print_command, logger=self.logger)
 
-
     @property
     def print_action(self):
         """\
         STILL UNDOCUMENTED
-        """
-        return self._print_action
-
 
-    @property
-    def config_file(self):
-        """\
-        STILL UNDOCUMENTED
         """
-        stdout = cStringIO.StringIO()
-        self.write(stdout)
-        return stdout.getvalue()
+        return self._print_action
 
 
 class X2goPrintAction(object):
@@ -149,6 +130,7 @@ class X2goPrintAction(object):
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: int
+
         """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -182,6 +164,7 @@ class X2goPrintAction(object):
 class X2goPrintActionPDFVIEW(X2goPrintAction):
     """\
     STILL UNDOCUMENTED
+
     """
     __name__= 'PDFVIEW'
     __decription__= 'View as PDF document'
@@ -197,7 +180,6 @@ class X2goPrintActionPDFVIEW(X2goPrintAction):
         self.pdfview_cmd = pdfview_cmd
         X2goPrintAction.__init__(self, *args, **kwargs)
 
-
     def do_print(self, pdf_file, job_title, spool_dir, ):
         """\
         STILL UNDOCUMENTED
@@ -220,6 +202,7 @@ class X2goPrintActionPDFVIEW(X2goPrintAction):
 class X2goPrintActionPDFSAVE(X2goPrintAction):
     """\
     STILL UNDOCUMENTED
+
     """
     __name__ = 'PDFSAVE'
     __decription__= 'Save as PDF'
@@ -229,16 +212,17 @@ class X2goPrintActionPDFSAVE(X2goPrintAction):
     def __init__(self, save_to_folder=None, *args, **kwargs):
         """\
         STILL UNDOCUMENTED
+
         """
         if save_to_folder is None:
             save_to_folder = os.path.expanduser(defaults.DEFAULT_PDFSAVE_LOCATION)
         self.save_to_folder = save_to_folder
         X2goPrintAction.__init__(self, *args, **kwargs)
 
-
     def do_print(self, pdf_file, job_title, spool_dir, ):
         """\
         STILL UNDOCUMENTED
+
         """
         dest_file = self._humanreadable_filename(pdf_file, job_title, target_path=self.save_to_folder)
         shutil.copy2(pdf_file, dest_file)
@@ -248,10 +232,10 @@ class X2goPrintActionPDFSAVE(X2goPrintAction):
         os.remove(_hr_filename)
 
 
-
 class X2goPrintActionPRINT(X2goPrintAction):
     """\
     STILL UNDOCUMENTED
+
     """
     __name__ = 'PRINT'
     __decription__= 'UNIX/Win32GDI printing'
@@ -259,14 +243,15 @@ class X2goPrintActionPRINT(X2goPrintAction):
     def __init__(self, printer=None, *args, **kwargs):
         """\
         STILL UNDOCUMENTED
+
         """
         self.printer = printer
         X2goPrintAction.__init__(self, *args, **kwargs)
 
-
     def do_print(self, pdf_file, job_title, spool_dir, ):
         """\
         STILL UNDOCUMENTED
+
         """
         _hr_filename = self._humanreadable_filename(pdf_file, job_title, spool_dir)
         shutil.copy2(pdf_file, _hr_filename)
@@ -302,6 +287,7 @@ class X2goPrintActionPRINT(X2goPrintAction):
 class X2goPrintActionPRINTCMD(X2goPrintAction):
     """\
     STILL UNDOCUMENTED
+
     """
     __name__      = 'PRINTCMD'
     __decription__= 'Print via a command (like LPR)'
@@ -309,6 +295,7 @@ class X2goPrintActionPRINTCMD(X2goPrintAction):
     def __init__(self, print_cmd=None, *args, **kwargs):
         """\
         STILL UNDOCUMENTED
+
         """
         if print_cmd is None:
             print_cmd = defaults.DEFAULT_PRINTCMD_CMD
@@ -319,6 +306,7 @@ class X2goPrintActionPRINTCMD(X2goPrintAction):
 class X2goPrintQueue(threading.Thread):
     """\
     STILL UNDOCUMENTED
+
     """
     print_action = None
 
@@ -336,6 +324,7 @@ class X2goPrintQueue(threading.Thread):
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: int
+
         """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -349,40 +338,38 @@ class X2goPrintQueue(threading.Thread):
         self.daemon = True
         self._accept_jobs = True
 
-
     def __del__(self):
         self.stop_thread()
 
-
     def pause(self):
         """\
         Prevent acceptance of new incoming print jobs. The processing of print jobs that 
         are currently still active will be completed, though.
+
         """
         if self._accept_jobs == True:
             self._accept_jobs = False
             self.logger('paused thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
 
-
     def resume(self):
         """\
         Resume operation of the X2go print spooler and continue accepting new incoming 
         print jobs.
+
         """
         if self._accept_jobs == False:
             self._accept_jobs = True
             self.logger('resumed thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
 
-
     def stop_thread(self):
         """\
         Stops this L{X2goRevFwTunnel} thread completely.
+
         """
         self.pause()
         self._keepalive = False
         self.logger('stopping thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
 
-
     @property
     def _incoming_print_jobs(self):
 
@@ -397,10 +384,10 @@ class X2goPrintQueue(threading.Thread):
             jobs.append((_job_file, pdf_filename, job_title))
         return [ j for j in jobs if j[1] not in self.active_jobs.keys() ]
 
-
     def set_print_action(self, print_action, **kwargs):
         """\
         STILL UNDOCUMENTED
+
         """
         if print_action in defaults.X2GO_PRINT_ACTIONS.keys():
             print_action = defaults.X2GO_PRINT_ACTIONS[print_action]
@@ -408,10 +395,10 @@ class X2goPrintQueue(threading.Thread):
         if print_action in defaults.X2GO_PRINT_ACTIONS.values():
             self.print_action = print_action(**kwargs)
 
-
     def run(self):
         """\
         STILL UNDOCUMENTED
+
         """
         self.logger('starting print queue thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
 
@@ -445,6 +432,7 @@ class X2goPrintQueue(threading.Thread):
 def x2go_printjob_handler(job_file=None, pdf_file=None, job_title=None, print_action=None, parent_thread=None, logger=None, ):
     """\
     STILL UNDOCUMENTED
+
     """
     if print_action is None:
         _printing = X2goClientPrinting(logger=logger)
@@ -467,10 +455,12 @@ def x2go_printjob_handler(job_file=None, pdf_file=None, job_title=None, print_ac
 class X2goPrintJob(threading.Thread):
     """\
     STILL UNDOCUMENTED
+
     """
     def __init__(self, **kwargs):
         """\
         STILL UNDOCUMENTED
+
         """
         threading.Thread.__init__(self, **kwargs)
         self.daemon = True
diff --git a/x2go/profiles.py b/x2go/profiles.py
index 04568a8..2ba13dc 100644
--- a/x2go/profiles.py
+++ b/x2go/profiles.py
@@ -22,359 +22,118 @@ X2goClientSessionProfile class - managing x2goclient session profiles.
 """
 __NAME__ = 'x2gosessionprofiles-pylib'
 
-#import os
-#import ConfigParser
-#import types
-#import exceptions
 
-#class _processINI(object):
-#    """
-#    Base class to process the different ini files used in x2go.
-#    Primarily used to standardize the content of the
-#    ini file.
-#    If entries are omitted in the file, they are filled with
-#    default values, so the resulting objects always contain
-#    the same fields
-#    """
-#    def __init__(self, fileName):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        self.writeconfig = False
-#        self.iniConfig = ConfigParser.SafeConfigParser()
-#        if fileName and os.path.exists(fileName):
-#            self.iniConfig.read(fileName)
-#
-#
-#    def fillDefaultsSection(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        for section, sectionvalue in self.defaultValues.items():
-#            for key, value in sectionvalue.items():
-#                if self.iniConfig.has_option(section,key): continue
-#                if not self.iniConfig.has_section(section):
-#                    self.iniConfig.add_section(section)
-#                self.storeValueTypes(section, key, value)
-#
-#
-#    def updValue(self, section, key, value):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        if not self.iniConfig.has_section(section):
-#            self.iniConfig.add_section(section)
-#        self.storeValueTypes(section, key, value)
-#        self.writeconfig = True
-#
-#
-#    def storeValueTypes(self, section, key, value):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        if type(value) is types.StringType:
-#            self.iniConfig.set(section,key,value)
-#        elif type(value) is types.BooleanType:
-#            if value:
-#                self.iniConfig.set(section,key,'1')
-#            else:
-#                self.iniConfig.set(section,key,'0')
-#        else:
-#            self.iniConfig.set(section,key,str(value))
-##
-#    def writeIni(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        if self.writeconfig:
-#            fd = open(self.fileName, 'wb')
-#            self.iniConfig.write(fd)
-#            fd.close()
-#            self.writeconfig = False
-#
-#    def getValue(self, section, key, getType=None):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        if self.iniConfig.has_option(section, key):
-#            if getType is None:
-#                return self.iniConfig.get(section, key)
-#            elif getType is types.BooleanType:
-#                return self.iniConfig.getboolean(section, key)
-#            elif getType is types.IntType:
-#                return self.iniConfig.getint(section, key)
-#
-#    def bldSessionObj(self):
-#        """
-#        This routine flattens the items making them simple
-#        object members
-#
-#        Note, it assumes the option is unique within the config!
-#        """
-#        for section in self.iniConfig.sections():
-#            for option in self.iniConfig.options(section):
-#                if section in self.defaultValues and option in self.defaultValues[section]:
-#                    setattr(self, option, self.getValue(section, option, type(self.defaultValues[section][option])))
-#                else:
-#                    setattr(self, option, self.getValue(section, option))
-#
-#
-#class X2goClientSettings(_processINI):
-#    """
-#    Settings object that  contains all data that is generally necessary
-#    """
-#    defaultValues = {       'LDAP':{'useldap':False,'port':389,'server':'localhost','port1':0,'port2':0}, \
-#                                'General':{'clientport':22,'autoresume':True}, \
-#                                'Authorization': {'newprofile':True,'suspend':True,'editprofile':True,'resume':True}
-#                        }
-#    def __init__(self, fileName=None):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        if fileName is None:
-#            fileName = os.path.normpath(os.path.expanduser('~/.x2goclient/settings'))
-#        _processINI.__init__(self, fileName)
-#        self.fillDefaultsSection()
-#        self.bldSessionObj()
-#
-#
-#class X2goClientSessionProfiles(_processINI):
-#    """
-#    Session object that contains several sessionProfiles that contain all data necessary to open the connection with
-#    an x2go server
-#    """
-#    defaultValues = \
-#         {'speed':2,'pack':'16m-jpeg','quality':9,'fstunnel':True,'export':'"/home/dick/Documenten:1;"','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, 'printing':True,'name':None,'icon':':icons/128x128/x2gosession.png','host':None,'user':None, 'key':None,
-#                   'sshport':22,'rootless':True,'applications':'dummy, WWWBROWSER, MAILCLIENT, OFFICE, TERMINAL','command':'dummy','rdpoptions':None,
-#                   'rdpserver':None,'default':False,'connected':False}
-#    def __init__(self, fileName=None):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        if fileName is None:
-#            fileName = os.path.normpath(os.path.expanduser('~/.x2goclient/sessions'))
-#        _processINI.__init__(self, fileName)
-#        self.SessionProfiles = self.iniConfig.sections()
-#        for section in self.SessionProfiles:
-#            for key, sectionvalue in self.defaultValues.items():
-#                if not self.iniConfig.has_option(section,key):
-#                    self.storeValueTypes(section, key, sectionvalue)
-#
-#    def getSection(self, section):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        return self.iniConfig.items(section)
-#
-#    def newProfile(self, name, **kw):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        for key, value in kw.items():
-#            if key in defaultValues:
-#                self.updValue(name, key, value)
-#            else:
-#                raise exceptions.X2goProfileException('Keyword %s not supported in profile' % key)
-#
-#        for key, value in defaultValues.items():
-#            if key in kw: continue
-#            self.storeValueTypes(name, key, value)
-#
-#
-#class X2goSingleSessionProfile(object):
-#    """\
-#    STILL UNDOCUMENTED
-#    """
-#
-#    def __init__(self, prof, profiles):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        self.prof = prof
-#        self.profiles = profiles
-#        self.session_uuid = None
-#        self.showConfigScreen = False
-#        self.bldSessionObj()
-#        if self.host is None:
-#            self.showConfigScreen = True
-#
-#
-#    def bldSessionObj(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        for option in self.profiles.iniConfig.options(self.prof):
-#            if self.prof in self.profiles.defaultValues and option in self.profiles.defaultValues[self.prof]:
-#                setattr(self, option, self.profiles.getValue(self.prof, option, type(self.profiles.defaultValues[self.prof][option])))
-#            else:
-#                setattr(self, option, self.profiles.getValue(self.prof, option))
-#
-#
-#    def updConfig(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        for key, retType in self.fieldList:
-#            self.updValue(self.prof, key, self.__dict__[key])
-#
-#
-#    def Connect(self, parent):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        printing = parent.printProfile
-#        geometry = str(self.width) + 'x' + str(self.height)
-#        self.c = x2go.X2goClient(logger=parent.liblogger)
-#        self.session_uuid = c.register_session(self.host, port=self.sshport,
-#                                                        username=self.user,
-#                                                       password=self.password,
-#                                                        key_filename=self.key,
-#                                                        add_to_known_hosts=self.add_to_known_hosts,
-#                                                        profile_name = self.name,
-#                                                        session_type=self.session_type,
-#                                                        link=self.link,
-#                                                        geometry=geometry,
-#                                                        pack=self.pack,
-#                                                        cache_type=self.cache_type,
-#                                                        kblayout=self.layout,
-#                                                        kbtype=self.type,
-#                                                        snd_system=self.sound,
-#                                                        printing=self.printing,
-#                                                        print_action=printing.print_action,
-#                                                        print_action_args=printing.print_action_args,
-#                                                        cmd=printing.command)
-#        self.c.session_start(session_uid)
-#        self.profiles.updValue(self.prof, 'connected', True)
-#        self.connected = True
-#        self.profiles.writeIni()
-#
-#    def Resume(self, parent, printing):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        pass
-#
-#
-#    def DisConnect(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        self.profiles.updValue(self.prof, 'connected', True)
-#        self.connected = False
-#        self.profiles.writeIni()
-#
-#
-#    def isAlive(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        return self.c.session_ok(self.session_uuid)
-#
-#
-#class X2goClientSessionProfiles(object):
-#    """\
- #   STILL UNDOCUMENTED
-#    """
-#
-#    def __init__(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        self.x2goprofs = []
-#        self.there_is_a_default = 0
-#        self.profiles = SessionProfiles()
- #       for prof in self.profiles.SessionProfiles:
-#            newSession = SingleProfile(prof, self.profiles)
-#            if newSession.default:
-#                self.x2goprofs.insert(0,newSession)
-#                self.there_is_a_default += 1
-#            else:
-#                self.x2goprofs.append(newSession)
-#        if len(self.profiles.SessionProfiles):
-#            self.current_profile = self.x2goprofs[0]
-#
-#    def Append(self, name, **kw):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        if self.profileExists(name):
-#            raise exceptions.X2goProfileException('Profile %s already exists' % name)
-#        else:
-#            self.profiles.newProfile(name, kw)
-#            self.x2goprofs.append(SingleProfile(name, self.profiles))
-#
-#    def writeIni(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        for s in self.x2goprofs:
-#            s.updConfig()
-#        self.profiles.writeIni()
-#
-#    def defaultAvailable(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        return self.there_is_a_default == 1
-#
-#    def profileExists(self, name):
-#        """\
- #       STILL UNDOCUMENTED
-#        """
-#        for profile in self.x2goprofs:
-#            if profile.prof == name or profile.name == name:
-#                self.current_profile = profile
-#                return True
-#        return False
-#
-#    def runningSessions(self):
-#        """\
-#        STILL UNDOCUMENTED
-##        """
-#        running = []
-#        for idx, profs in enumerate(self.profiles.iniConfig.sections()):
-#            connected = self.profiles.getValue(profs, 'connected', getType='bool')
-#            if connected:
-#                running.append(x2goprofs[idx])
-#        return running
-#
-#    def suspendedSessions(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        running = self.runningSessions()
-#        suspended = []
-#        for idx, run in enumerate(running):
-#            if running.isAlive(): continue
-#            suspended.appended(run)
-#        return suspended
-#
-#    def anyRunningSessions(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        return len(self.runningSessions()) > 0
-#
-#    def listAllAvailableSessions(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        availableSessions = []
-#        for idx, profs in enumerate(self.profiles.iniConfig.sections()):
-#            availableSessions.append([self.profiles.getValue(profs, 'name'), self.profiles.getValue(profs, 'connected', getType='bool')])
-#        return availableSessions
-#
-#    def listNonRunningProfiles(self):
-#        """\
-#        STILL UNDOCUMENTED
-#        """
-#        nonrunning = []
-#        for idx, profs in enumerate(self.profiles.iniConfig.sections()):
-#            connected = self.profiles.getValue(profs, 'connected', getType='bool')
-#            if not connected:
-#                nonrunning.append(self.profiles.getValue(profs,'name'))
-#        return nonrunning
-#
-#
\ No newline at end of file
+# Python X2go modules
+from defaults import X2GO_SESSIONPROFILES_CONFIGFILES
+from defaults import X2GO_SESSIONPROFILE_DEFAULTS
+import inifiles
+import log
+import utils
+from x2go_exceptions import X2goProfileException
+
+
+class X2goClientSessions(inifiles.X2goIniFile):
+
+    defaultValues = {}
+    defaultSessionProfile = X2GO_SESSIONPROFILE_DEFAULTS
+    _non_profile_sections = ('embedded')
+
+    def __init__(self, config_files=X2GO_SESSIONPROFILES_CONFIGFILES, defaults=None, session_profile_defaults=None, logger=None, loglevel=log.loglevel_DEFAULT):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        # providing defaults for an X2goSessionProfiles instance will---in the worst case---override your 
+        # existing sessions file in your home directory once you write the sessions back to file...
+        inifiles.X2goIniFile.__init__(self, config_files, defaults=defaults, logger=logger, loglevel=loglevel)
+
+        if utils._checkSessionProfileDefaults(session_profile_defaults):
+            self.defaultSessionProfile = session_profile_defaults
+
+        self.session_profiles = self.iniConfig.sections()
+        for session_profile in self.session_profiles:
+            for key, default_value in self.defaultSessionProfile.iteritems():
+                if not self.iniConfig.has_option(session_profile, key):
+                    self._storeValue(session_profile, key, default_value)
+        self._updateDataObject()
+
+    def get_profile_config(self, profile_id):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        if (not profile_id in self.profile_ids) or (profile_id in self._non_profile_sections):
+            raise X2goProfileException('No X2go session profile with Id %s' % profile_id)
+        _profile_config = {}
+        for key in self.iniConfig.options(profile_id):
+            _profile_config[key] = self.get(profile_id, key, key_type=self.get_type(key))
+        return _profile_config or None
+
+    def get_type(self, key):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return type(self.defaultSessionProfile[key])
+
+    @property
+    def profile_ids(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return [ s for s in self.iniConfig.sections() if s not in self._non_profile_sections ]
+
+    @property
+    def profile_names(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return [ self.get_profile_name(p) for p in self.profile_ids ]
+
+    def get_profile_id(self, profile_name):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        _profile_ids = [ p for p in self.profile_ids if self.get_profile_name(p) == profile_name ]
+        if len(_profile_ids) == 1:
+            return _profile_ids[0]
+        elif len(_profile_ids) == 0:
+            return None
+        else:
+            raise X2goProfileException('The sessions config file contains multiple session profiles with name: %s' % profile_name)
+
+    def get_profile_name(self, profile_id):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.get_profile_config(profile_id)['name']
+
+    def add_profile(self, profile_id, **kwargs):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        for key, value in kwargs.items():
+            if key in self.defaultSessionProfile:
+                self.update(profile_id, key, value)
+            else:
+                raise X2goProfileException('keyword ,,%s\'\' not supported in X2go session profile' % key)
+
+        for key, value in self.defaultSessionProfile.items():
+            if key in kwargs: continue
+            self._storeValueTypes(profile_id, key, value)
+
+    def delete_profile(self, profile_id):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        self.iniConfig.remove_section(profile_id)
+        self.write_user_config = True
+        self.writeIniFile()
+
+
diff --git a/x2go/proxy.py b/x2go/proxy.py
index aeb43f5..85d0691 100644
--- a/x2go/proxy.py
+++ b/x2go/proxy.py
@@ -19,6 +19,7 @@
 
 """\
 X2goProxy classes - proxying your connection through NX3 and others.
+
 """
 __NAME__ = 'x2goproxy-pylib'
 
@@ -39,6 +40,7 @@ class X2goProxy(object):
 
     This class needs to be inherited from a concrete proxy class. Only 
     currently available proxy class is: L{X2goNX3Proxy}.
+
     """
     PROXY_CMD = ''
     """Proxy command. Needs to be set by a potential child class, might be OS specific."""
@@ -68,6 +70,7 @@ class X2goProxy(object):
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: int
+
         """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -80,11 +83,11 @@ class X2goProxy(object):
         self.session_log = session_log
         self.PROXY_ENV = os.environ.copy()
 
-
     def __del__(self):
         """\
         Close any left open port forwarding tunnel, also close session log file, 
         if left open.
+
         """
         if self.proxy is not None and self.proxy.poll() is None:
             self.logger('Shutting down X2go proxy subprocess', log.loglevel_DEBUG)
@@ -97,12 +100,12 @@ class X2goProxy(object):
         if self.session_log_stderr is not None:
             self.session_log_stderr.close()
 
-
     def start(self):
         """\
         Start the X2go proxy command. The X2go proxy command utilizes a
         Paramiko/SSH based forwarding tunnel (openssh -L option). This tunnel
         gets started here and is forked into background (Greenlet/gevent).
+
         """
         if self.session_info is None or self.ssh_transport is None:
             return None
@@ -141,10 +144,12 @@ class X2goNX3Proxy(X2goProxy):
 
     It basically fills X2goProxy variables with sensible content. Its 
     methods mostly wrap around the corresponding methods of the parent class.
+
     """
     def __init__(self, *args, **kwargs):
         """\
         For available parameters refer to L{X2goProxy} class documentation.
+
         """
         X2goProxy.__init__(self, *args, **kwargs)
 
diff --git a/x2go/rforward.py b/x2go/rforward.py
index 400e76b..8161338 100644
--- a/x2go/rforward.py
+++ b/x2go/rforward.py
@@ -52,6 +52,7 @@ def x2go_transport_tcp_handler(chan, (origin_addr, origin_port), (server_addr, s
     If the server port of an incoming Paramiko/SSH channel matches the configured port of an L{X2goRevFwTunnel} 
     instance, this instance gets notified of the incoming channel and a new L{X2goRevFwChannelThread} is 
     started. This L{X2goRevFwChannelThread} then takes care of the new channel's incoming data stream.
+
     """
     transport = chan.get_transport()
     transport._queue_incoming_channel(chan)
@@ -70,6 +71,7 @@ class X2goRevFwTunnel(threading.Thread):
     L{X2goRevFwTunnel} class objects are used to reversely tunnel 
     X2go audio, X2go printing and X2go folder sharing / device mounting
     through Paramiko/SSH.
+
     """
     def __init__(self, server_port, remote_host, remote_port, ssh_transport, logger=None, loglevel=log.loglevel_DEFAULT):
         """\
@@ -97,6 +99,7 @@ class X2goRevFwTunnel(threading.Thread):
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: int
+
         """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -116,34 +119,32 @@ class X2goRevFwTunnel(threading.Thread):
         self.daemon = True
         self._accept_channels = True
 
-
     def __del__(self):
         self.stop_thread()
 
-
     def pause(self):
         """\
         Prevent acceptance of new incoming connections through the Paramiko/SSH 
         reverse forwarding tunnel. Also, any active connection on this L{X2goRevFwTunnel} 
         instance is closed immediately, if this method is called.
+
         """
         if self._accept_channels == True:
             self.ssh_transport.cancel_port_forward('', self._requested_port)
             self._accept_channels = False
             self.logger('paused thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
 
-
     def resume(self):
         """\
         Resume operation of the Paramiko/SSH reverse forwarding tunnel
         and continue accepting new incoming connections.
+
         """
         if self._accept_channels == False:
             self._accept_channels = True
             self._requested_port = self.ssh_transport.request_port_forward('', self.server_port, handler=x2go_transport_tcp_handler)
             self.logger('resumed thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
 
-
     def notify(self):
         """\
         Notify an L{X2goRevFwTunnel} instance of an incoming Paramiko/SSH channel.
@@ -154,23 +155,23 @@ class X2goRevFwTunnel(threading.Thread):
 
         The sent notification will trigger a C{thread.Condition()} waiting for notification
         in L{X2goRevFwTunnel.run()}.
+
         """
         self.incoming_channel.acquire()
         self.logger('notifying thread of incoming channel: %s' % repr(self), loglevel=log.loglevel_DEBUG)
         self.incoming_channel.notify()
         self.incoming_channel.release()
 
-
     def stop_thread(self):
         """\
         Stops this L{X2goRevFwTunnel} thread completely.
+
         """
         self.pause()
         self._keepalive = False
         self.logger('stopping thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
         self.notify()
 
-
     def run(self):
         """\
         This method gets run once an L{X2goRevFwTunnel} has been started with its
@@ -190,6 +191,7 @@ class X2goRevFwTunnel(threading.Thread):
         The channel will last till the connection gets dropped on the X2go server side or 
         until the tunnel gets paused by an L{X2goRevFwTunnel.pause()} call or stopped via the
         L{X2goRevFwTunnel.stop_thread()} method.
+
         """
         self._requested_port = self.ssh_transport.request_port_forward('', self.server_port, handler=x2go_transport_tcp_handler)
         self._keepalive = True
@@ -235,6 +237,7 @@ def x2go_rev_forward_channel_handler(chan=None, addr='', port=0, parent_thread=N
         of L{X2goRevFwTunnel.pause()} on the instance can be used to shut down all incoming 
         tunneled SSH connections associated to this L{X2goRevFwTunnel} instance
         from within a Python X2go application.
+
     """
     fw_socket = socket.socket()
     if logger is None:
@@ -273,6 +276,7 @@ class X2goRevFwChannelThread(threading.Thread):
     """\
     Starts a thread for each incoming Paramiko/SSH data channel trough the reverse
     forwarding tunnel.
+
     """
     def __init__(self, channel, remote=None, **kwargs):
         """\
@@ -281,6 +285,7 @@ class X2goRevFwChannelThread(threading.Thread):
         @type channel: class
         @param remote: tuple (addr, port) that specifies the data endpoint of the channel
         @type remote: (str, int)
+
         """
         self.channel = channel
         if remote is not None:
@@ -288,5 +293,3 @@ class X2goRevFwChannelThread(threading.Thread):
             self.remote_port = remote[1]
         threading.Thread.__init__(self, **kwargs)
         self.daemon = True
-
-
diff --git a/x2go/session.py b/x2go/session.py
index 5b1c904..766d53b 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -19,6 +19,7 @@
 
 """\
 X2goSession class - core functions for handling your individual X2go sessions.
+
 """
 __NAME__ = 'x2gosession-pylib'
 
@@ -39,7 +40,7 @@ import printing
 import log
 import defaults
 import utils
-import exceptions
+import x2go_exceptions
 import guardian
 
 from cleanup import x2go_cleanup 
@@ -54,7 +55,7 @@ from defaults import X2GO_SESSION_ROOTDIR as _X2GO_SESSION_ROOTDIR
 _X2GO_SESSION_OPTIONS = ('geometry', 'depth', 'link', 'pack',
                          'cache_type', 'kblayout', 'kbtype',
                          'session_type', 'snd_system', 'cmd',
-                         'rootdir', 'loglevel',
+                         'rootdir', 'loglevel', 'profile_name', 'profile_id',
                          'print_action', 'print_action_args',
                          'proxy_class', 'logger',
                        )
@@ -82,6 +83,7 @@ class X2goSessionParams(object):
     """\
     The L{X2goSessionParams} class is used to store all parameters that
     L{X2goSession} objects are constructed with.
+
     """
     def rewrite_session_type(self):
         """\
@@ -95,6 +97,7 @@ class X2goSessionParams(object):
         @return: 'D' if session should probably a desktop session,
             'R' (for rootless) else
         @rtype: str
+
         """
         session_type = self.session_type
         cmd = self.cmd
@@ -110,7 +113,6 @@ class X2goSessionParams(object):
                 return
         self.session_type = 'R'
 
-
     def update(self, properties_to_be_updated={}):
         """\
         Update all properties in the object L{X2goSessionParams} object from
@@ -120,8 +122,8 @@ class X2goSessionParams(object):
             property names as keys und their values to be update in 
             L{X2goSessionParams} object.
         @type properties_to_be_updated: dict
-        """
 
+        """
         for key in properties_to_be_updated.keys():
             setattr(self, key, properties_to_be_updated[key] or '')
         self.rewrite_session_type()
@@ -132,6 +134,7 @@ class X2goServerSessionInfo(object):
     L{X2goServerSessionInfo} is used to store all information
     that is retrieved from the connected X2go server on 
     L{X2goSession.start()} resp. L{X2goSession.resume()}.
+
     """
     def __str__(self):
         return self.name
@@ -141,6 +144,7 @@ class X2goServerSessionInfo(object):
     def _parse_x2golistsessions_line(self, x2go_output):
         """\
         Parse a single line of X2go's listsessions output.
+
         """
         l = x2go_output.split("|")
         self.name = l[1]
@@ -162,6 +166,7 @@ class X2goServerSessionInfo(object):
     def _parse_x2gostartagent_output(self, x2go_output):
         """\
         Parse x2gostartagent output.
+
         """
         l = x2go_output.split("\n")
         self.name = l[3]
@@ -196,6 +201,7 @@ class X2goServerSessionInfo(object):
         @type local_container: str
         @param remote_container: X2go server session directory for config files, cache and session logs
         @type remote_container: str
+
         """
         self._parse_x2gostartagent_output(x2go_output)
         self.username = username
@@ -206,6 +212,7 @@ class X2goServerSessionInfo(object):
     def clear(self):
         """\
         Clear all properties of a L{X2goServerSessionInfo} object.
+
         """
         self.name = ''
         self.cookie = ''
@@ -230,6 +237,7 @@ class X2goServerSessionList(object):
     L{X2goServerSessionList} is used to store all information
     that is retrieved from a connected X2go server on a
     L{X2goSession.list_sessions()} call.
+
     """
     sessions = {}
 
@@ -239,6 +247,7 @@ class X2goServerSessionList(object):
             session separated by a newline character. Session values are separated 
             by Unix Pipe Symbols ('|')
         @type x2go_output: str
+
         """
         lines = x2go_output.split("\n")
         for line in lines:
@@ -314,6 +323,7 @@ class X2goSession(paramiko.SSHClient):
     @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
         constructed with the given loglevel
     @type loglevel: int
+
     """
     associated = False
     params = None
@@ -336,6 +346,7 @@ class X2goSession(paramiko.SSHClient):
                  cache_type="unix-kde", kblayout='us', kbtype='pc105/us',
                  session_type="application", snd_system='pulse', cmd=None,
                  rootdir=None, proxy_class=None,
+                 profile_name='UNKNOWN', profile_id=utils._genSessionProfileId(),
                  print_action=None, print_action_args={},
                  logger = None, loglevel=log.loglevel_DEFAULT,
                  *args, **kwargs):
@@ -343,8 +354,8 @@ class X2goSession(paramiko.SSHClient):
         Initialize an X2go session. With the X2goSession class you can start
         new X2go sessions, resume suspended sessions or suspend resp. terminate
         currently running sessions on a connected X2go server.
-        """
 
+        """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
         else:
@@ -378,11 +389,9 @@ class X2goSession(paramiko.SSHClient):
         self._mk_session_rootdir(self.params.rootdir)
         paramiko.SSHClient.__init__(self, *args, **kwargs)
 
-
     def __del__(self):
         self._x2go_tidy_up()
 
-
     def _mk_session_rootdir(self, d):
 
         try:
@@ -406,13 +415,11 @@ class X2goSession(paramiko.SSHClient):
         else:
             raise exceptions.X2goSessionException('the Paramiko/SSH client is not connected')
 
-
     def _x2go_sftp_put(self, local_path, remote_path, loglevel=log.loglevel_INFO):
 
         self.logger('sFTP-put: %s -> %s:%s' % (local_path, self.session_info.hostname, remote_path), loglevel)
         self.sftp_client.put(local_path, remote_path)
 
-
     def _x2go_sftp_write(self, remote_path, content, loglevel=log.loglevel_INFO):
 
         self.logger('sFTP-write: opening remote file %s on host %s for writing' % (remote_path, self.session_info.hostname), loglevel=log.loglevel_DEBUG)
@@ -421,13 +428,11 @@ class X2goSession(paramiko.SSHClient):
         remote_fileobj.write(content)
         remote_fileobj.close()
 
-
     def _x2go_sftp_remove(self, remote_path, loglevel=log.loglevel_INFO):
 
         self.logger('sFTP-write: removing remote file %s on host %s' % (remote_path, self.session_info.hostname), loglevel)
         self.sftp_client.remove(remote_path)
 
-
     @property
     def _x2go_remote_home(self):
 
@@ -438,14 +443,12 @@ class X2goSession(paramiko.SSHClient):
         else:
             return self._remote_home
 
-
     @property
     def _x2go_session_auth_rsakey(self):
         if self._session_auth_rsakey is None:
             self._session_auth_rsakey = paramiko.RSAKey.generate(defaults.RSAKEY_STRENGTH)
         return self._session_auth_rsakey
 
-
     def _x2go_tidy_up(self):
 
         if self.proxy is not None:
@@ -527,6 +530,7 @@ class X2goSession(paramiko.SSHClient):
         @raise SSHException: if there was any other error connecting or
             establishing an SSH session
         @raise socket.error: if a socket error occurred while connecting
+
         """
         if add_to_known_hosts:
             self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -581,13 +585,13 @@ class X2goSession(paramiko.SSHClient):
         self.guardian_thread.start()
         self.guardian_thread.active_threads.append(self.get_transport())
 
-
     def start(self, **kwargs):
         """\
         Start a new X2go session. 
 
         The L{X2goSession.start()} method accepts any parameter
         that can be passed to the class constructor.
+
         """
         self.params.update(kwargs)
 
@@ -626,7 +630,6 @@ class X2goSession(paramiko.SSHClient):
 
         self.associated = True
 
-
     def start_sound(self):
         """\
         Initialize Paramiko/SSH reverse forwarding tunnel for X2go sound.
@@ -635,6 +638,7 @@ class X2goSession(paramiko.SSHClient):
 
             - Pulse Audio
             - Esound 
+
         """
         _tunnel = None
         ssh_transport = self.get_transport()
@@ -691,10 +695,10 @@ class X2goSession(paramiko.SSHClient):
             # tunnel has already been started and might simply need a resume call
             ssh_transport.reverse_tunnels['snd'][1].resume()
 
-
     def start_sshfs(self):
         """\
         Initialize Paramiko/SSH reverse forwarding tunnel for X2go folder sharing.
+
         """
         # start reverse SSH tunnel for sshfs (folder sharing, printing)
         ssh_transport = self.get_transport()
@@ -715,7 +719,6 @@ class X2goSession(paramiko.SSHClient):
             # tunnel has already been started and might simply need a resume call
             ssh_transport.reverse_tunnels['sshfs'][1].resume()
 
-
     def _x2go_pause_rev_fw_tunnel(self, name):
         # pause reverse SSH tunnel of name <name>
         ssh_transport = self.get_transport()
@@ -723,24 +726,24 @@ class X2goSession(paramiko.SSHClient):
         if _tunnel is not None:
             _tunnel.pause()
 
-
     def stop_sound(self):
         """\
         Shutdown (pause) Paramiko/SSH reverse forwarding tunnel for X2go sound.
+
         """
         self._x2go_pause_rev_fw_tunnel('sound')
 
-
     def stop_sshfs(self):
         """\
         Shutdown (pause) Paramiko/SSH reverse forwarding tunnel for X2go folder sharing.
+
         """
         self._x2go_pause_rev_fw_tunnel('sshfs')
 
-
     def start_printing(self):
         """\
         Initialize X2go print spooling.
+
         """
         spool_dir = '%s/spool' % self.session_info.local_container
         if not os.path.exists(spool_dir):
@@ -754,10 +757,10 @@ class X2goSession(paramiko.SSHClient):
         self.print_queue.start()
         self.guardian_thread.active_threads.append(self.print_queue)
 
-
     def set_print_action(self, print_action, **kwargs):
         """\
         STILL UNDOCUMENTED
+
         """
         self.print_queue.set_print_action(print_action, logger=self.logger, **kwargs)
 
@@ -765,11 +768,11 @@ class X2goSession(paramiko.SSHClient):
     def stop_printing(self):
         """\
         Shutdown (pause) the X2go Print Queue thread.
+
         """
         if self.print_queue is not None:
             self.print_queue.pause()
 
-
     def share_local_folder(self, folder_name=None, folder_type='disk'):
         """\
         Share a local folder with the X2go session.
@@ -783,6 +786,7 @@ class X2goSession(paramiko.SSHClient):
 
         @return: returns C{True} if the local folder has been successfully mounted within the X2go server session
         @rtype: bool
+
         """
         if folder_name is None:
             self.logger('no folder name given...', log.loglevel_WARN)
@@ -838,7 +842,6 @@ class X2goSession(paramiko.SSHClient):
         (stdin, stdout, stderr) = self._x2go_exec_command(cmd_line)
         self.logger('x2gomountdirs output is : %s' % stdout.read().split('\n'), log.loglevel_INFO)
 
-
     def run_command(self, cmd=None):
         """\
         Run a command in this session.
@@ -853,6 +856,7 @@ class X2goSession(paramiko.SSHClient):
         @return: stdout.read() and stderr.read() as returned by the run command
             on the X2go server
         @rtype: tuple of str
+
         """
         if cmd in ("", None):
             if self.params.cmd is None:
@@ -880,7 +884,6 @@ class X2goSession(paramiko.SSHClient):
 
         return stdout.read(), stderr.read()
 
-
     def list_sessions(self, raw=False):
         """\
         List all sessions of current user on the connected server.
@@ -893,6 +896,7 @@ class X2goSession(paramiko.SSHClient):
             if the raw argument is set, the plain text output of the x2golistsessions 
             command is returned
         @rtype: L{X2goServerSessionList} instance or str
+
         """
         (stdin, stdout, stderr) = self._x2go_exec_command("x2golistsessions")
 
@@ -902,7 +906,6 @@ class X2goSession(paramiko.SSHClient):
         sessions = X2goServerSessionList(stdout.read()).sessions
         return sessions
 
-
     def ok(self):
         """\
         Returns C{True} if this X2go session is up and running, 
@@ -910,10 +913,10 @@ class X2goSession(paramiko.SSHClient):
 
         @return: X2go session OK?
         @rtype: bool
+
         """
         return bool(self.session_info.name and (self.proxy_subprocess and self.proxy_subprocess.poll() is None))
 
-
     def is_running(self):
         """\
         Returns C{True} if this X2go session is in running state ('R'), 
@@ -921,13 +924,13 @@ class X2goSession(paramiko.SSHClient):
 
         @return: X2go session running?
         @rtype: bool
+
         """
         session_infos = self.list_sessions()
         if self.session_info.name in session_infos.keys():
             return session_infos[self.session_info.name].status == "R"
         return False
 
-
     def is_suspended(self):
         """\
         Returns C{True} if this X2go session is in suspended state ('S'), 
@@ -935,13 +938,13 @@ class X2goSession(paramiko.SSHClient):
 
         @return: X2go session suspended?
         @rtype: bool
+
         """
         session_infos = self.list_sessions()
         if self.session_info.name in session_infos.keys():
             return session_infos[self.session_info.name].status == "S"
         return False
 
-
     def has_terminated(self):
         """\
         Returns C{True} if this X2go session is not in the session list on the 
@@ -952,11 +955,11 @@ class X2goSession(paramiko.SSHClient):
 
         @return: X2go session has terminate?
         @rtype: bool
+
         """
         session_infos = self.list_sessions()
         return self.session_info.name not in session_infos.keys()
 
-
     def associate(self, session_name):
         """\
         Associate L{session_name} with an available (state 'R' or 'S')
@@ -964,6 +967,7 @@ class X2goSession(paramiko.SSHClient):
 
         @param session_name: X2go name of an available session.
         @type session_name: str
+
         """
         self.associated = False
         try:
@@ -977,7 +981,6 @@ class X2goSession(paramiko.SSHClient):
             pass
         return self.associated
 
-
     def resume(self, **kwargs):
         """\
         Resume a running/suspended X2go session. 
@@ -987,6 +990,7 @@ class X2goSession(paramiko.SSHClient):
 
         @return: True if the session could be successfully resumed
         @rtype: bool
+
         """
         if self.associated:
             self.params.update(kwargs)
@@ -1038,6 +1042,7 @@ class X2goSession(paramiko.SSHClient):
 
         @return: True if the session could be successfully suspended
         @rtype: bool
+
         """
         _ret = False
         if session_name is not None:
@@ -1061,7 +1066,6 @@ class X2goSession(paramiko.SSHClient):
 
         return _ret
 
-
     def terminate(self, session_name=None):
         """\
         Terminate either this or another available X2go session on the connected
@@ -1075,6 +1079,7 @@ class X2goSession(paramiko.SSHClient):
 
         @return: True if the session could be successfully terminate
         @rtype: bool
+
         """
         _ret = False
         if session_name is not None:
@@ -1088,7 +1093,7 @@ class X2goSession(paramiko.SSHClient):
         elif self.associated:
 
             self.logger('terminating associated session: %s' % self.session_info, log.loglevel_INFO)
-            (stdin, stdout, stderr) = self.exec_command("x2goterminate-session %s" % self.session_info, loglevel=log.loglevel_DEBUG)
+            (stdin, stdout, stderr) = self._x2go_exec_command("x2goterminate-session %s" % self.session_info, loglevel=log.loglevel_DEBUG)
             dummy_stdout = stdout.read()
             dummy_stderr = stderr.read()
             self.session_info.clear()
diff --git a/x2go/settings.py b/x2go/settings.py
index 3c01824..c2ad480 100644
--- a/x2go/settings.py
+++ b/x2go/settings.py
@@ -24,23 +24,26 @@ __NAME__ = 'x2gosettings-pylib'
 
 # modules
 import os
-import ConfigParser
-import StringIO
 
 # Python X2go modules
-from defaults import LOCAL_HOME as _LOCAL_HOME
+import log
+from defaults import LOCAL_HOME as _current_home
 from defaults import X2GO_CLIENT_ROOTDIR as _X2GO_CLIENT_ROOTDIR
+from defaults import X2GO_SETTINGS_CONFIGFILES
+from defaults import X2GO_CLIENTSETTINGS_DEFAULTS
+import inifiles
 
-DEFAULT_PRINTING_CONFIGS = [
-    '/etc/x2goclient/printing',
-    os.path.join(_LOCAL_HOME, _X2GO_CLIENT_ROOTDIR, 'printing'),
-]
 
-
-class X2goClientSettings(ConfigParser.SafeConfigParser):
+class X2goClientSettings(inifiles.X2goIniFile):
     """\
-    NOT IMPLEMENTED YET
+    (Generally) file based settings for X2goClient instances.
+
     """
-    def load(self):
-        pass
+    defaultValues = X2GO_CLIENTSETTINGS_DEFAULTS
+
+    def __init__(self, config_files=X2GO_SETTINGS_CONFIGFILES, defaults=None, logger=None, loglevel=log.loglevel_DEFAULT):
+        """\
+        STILL UNDOCUMENTED
 
+        """
+        inifiles.X2goIniFile.__init__(self, config_files, defaults=defaults, logger=logger, loglevel=loglevel)
diff --git a/x2go/sftpserver.py b/x2go/sftpserver.py
index a7ab7b1..49af2b2 100644
--- a/x2go/sftpserver.py
+++ b/x2go/sftpserver.py
@@ -27,6 +27,7 @@ does not need a locally installed SSH daemon on the client side machine.
 
 The Python X2go sFTP server code was originally written by Richard Murri, 
 for further information see his website: http://www.richardmurri.com
+
 """
 __NAME__ = "x2gosftpserver-pylib"
 
@@ -47,10 +48,12 @@ class _SSHServer(paramiko.ServerInterface):
     """\
     Implementation of a basic SSH server that is supposed 
     to run with his sFTP server implementation.
+
     """
     def __init__(self, auth_key=None, logger=None, loglevel=log.loglevel_DEFAULT, *args, **kwargs):
         """\
         Initialize a new sFTP server interface.
+
         """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -66,15 +69,16 @@ class _SSHServer(paramiko.ServerInterface):
     def check_channel_request(self, kind, chanid):
         """\
         Only allow session requests.
+
         """
         if kind == 'session':
             return paramiko.OPEN_SUCCEEDED
         return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
 
-
     def check_auth_publickey(self, username, key):
         """\
         Ensure proper authentication.
+
         """
         if username == self.current_local_user:
             self.logger('sFTP server %s: username is %s' % (self, self.current_local_user), loglevel=log.loglevel_DEBUG)
@@ -84,10 +88,10 @@ class _SSHServer(paramiko.ServerInterface):
         self.logger('sFTP server %s: publickey auth failed' % (self), loglevel=log.loglevel_WARN)
         return paramiko.AUTH_FAILED
 
-
     def get_allowed_auths(self, username):
         """\
         Only allow public key authentication.
+
         """
         return 'publickey'
 
@@ -95,6 +99,7 @@ class _SSHServer(paramiko.ServerInterface):
 class _SFTPHandle(paramiko.SFTPHandle):
     """\
     Represents a handle to an open file.
+
     """
     def stat(self):
         try:
@@ -106,10 +111,12 @@ class _SFTPHandle(paramiko.SFTPHandle):
 class _SFTPServerInterface(paramiko.SFTPServerInterface):
     """\
     sFTP server implementation.
+
     """
     def __init__(self, server, chroot=None, logger=None, loglevel=log.loglevel_DEFAULT, server_event=None, *args, **kwargs):
         """\
         Make user information accessible as well as set chroot jail directory.
+
         """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -121,7 +128,6 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
         self.logger('sFTP server: initializing new channel...', loglevel=log.loglevel_DEBUG)
         self.CHROOT = chroot or '/tmp'
 
-
     def _realpath(self, path):
         """\
         Enforce the chroot jail.
@@ -130,10 +136,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
         path = path.replace('//','/')
         return path
 
-
     def list_folder(self, path):
         """\
         List the contents of a folder.
+
         """
         path = self._realpath(path)
         self.logger('sFTP server: listing files in folder: %s' % path, loglevel=log.loglevel_DEBUG_SFTPXFER)
@@ -157,10 +163,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             self.logger('sFTP server %s: encountered error: %s' % (self, str(e)), loglevel=log.loglevel_DEBUG_SFTPXFER)
             return paramiko.SFTPServer.convert_errno(e.errno)
 
-
     def stat(self, path):
         """\
         Stat on a file.
+
         """
         path = self._realpath(path)
         self.logger('sFTP server %s: calling stat on path: %s' % (self, path), loglevel=log.loglevel_DEBUG_SFTPXFER)
@@ -170,10 +176,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             self.logger('sFTP server %s: encountered error: %s' % (self, str(e)), loglevel=log.loglevel_DEBUG_SFTPXFER)
             return paramiko.SFTPServer.convert_errno(e.errno)
 
-
     def lstat(self, path):
         """\
         LStat on a file.
+
         """
         path = self._realpath(path)
         self.logger('sFTP server: calling lstat on path: %s' % path, loglevel=log.loglevel_DEBUG_SFTPXFER)
@@ -183,7 +189,6 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             self.logger('sFTP server %s: encountered error: %s' % (self, str(e)), loglevel=log.loglevel_DEBUG_SFTPXFER)
             return paramiko.SFTPServer.convert_errno(e.errno)
 
-
     def open(self, path, flags, attr):
         """\
         Open a file.for reading, writing, appending etc.
@@ -230,7 +235,6 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
         fobj.writefile = f
         return fobj
 
-
     def remove(self, path):
         """\
         Remove a file.
@@ -239,10 +243,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
         self.logger('sFTP server %s: removing file: %s' % (self, path), loglevel=log.loglevel_DEBUG_SFTPXFER)
         return paramiko.SFTP_OK
 
-
     def rename(self, oldpath, newpath):
         """\
         Rename/Move a file.
+
         """
         self.logger('sFTP server %s: renaming path from %s to %s' % (self, oldpath, newpath), loglevel=log.loglevel_DEBUG_SFTPXFER)
         oldpath = self._realpath(oldpath)
@@ -254,10 +258,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             return paramiko.SFTPServer.convert_errno(e.errno)
         return paramiko.SFTP_OK
 
-
     def mkdir(self, path, attr):
         """\
         Make a directory.
+
         """
         self.logger('sFTP server: creating new dir (perms: %s): %s' % (attr.st_mode, path), loglevel=log.loglevel_DEBUG_SFTPXFER)
         path = self._realpath(path)
@@ -268,10 +272,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             return paramiko.SFTPServer.convert_errno(e.errno)
         return paramiko.SFTP_OK
 
-
     def rmdir(self, path):
         """\
         Remove a directory (if needed recursively).
+
         """
         self.logger('sFTP server %s: removing dir: %s' % (self, path), loglevel=log.loglevel_DEBUG_SFTPXFER)
         path = self._realpath(path)
@@ -282,10 +286,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             return paramiko.SFTPServer.convert_errno(e.errno)
         return paramiko.SFTP_OK
 
-
     def chattr(self, path, attr):
         """\
         Change file attributes.
+
         """
         self.logger('sFTP server %s: modifying attributes of path: %s' % (self, path), loglevel=log.loglevel_DEBUG_SFTPXFER)
         path = self._realpath(path)
@@ -299,10 +303,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             return paramiko.SFTPServer.convert_errno(e.errno)
         return paramiko.SFTP_OK
 
-
     def symlink(self, target_path, path):
         """\
         Create a symbolic link.
+
         """
         self.logger('sFTP server %s: creating symlink from: %s to target: %s' % (self, path, target_path), loglevel=log.loglevel_DEBUG_SFTPXFER)
         path = self._realpath(path)
@@ -315,10 +319,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             return paramiko.SFTPServer.convert_errno(e.errno)
         return paramiko.SFTP_OK
 
-
     def readlink(self, path):
         """\
         Read the target of a symbolic link.
+
         """
         path = self._realpath(path)
         try:
@@ -327,10 +331,10 @@ class _SFTPServerInterface(paramiko.SFTPServerInterface):
             self.logger('sFTP server %s: encountered error: %s' % (self, str(e)), loglevel=log.loglevel_DEBUG_SFTPXFER)
             return paramiko.SFTPServer.convert_errno(e.errno)
 
-
     def session_ended(self):
         """\
         Tidy up when the sFTP session has ended.
+
         """
         if self.server_event is not None:
             self.logger('sFTP server %s: session has ended' % self, loglevel=log.loglevel_DEBUG_SFTPXFER)
@@ -342,6 +346,7 @@ class X2goRevFwTunnelToSFTP(rforward.X2goRevFwTunnel):
     A reverse fowarding tunnel with an sFTP server at its endpoint. This blend of a Paramiko/SSH
     reverse forwarding tunnel is used to provide access to local X2go client folders 
     from within the the remote X2go server session.
+
     """
     def __init__(self, server_port, ssh_transport, auth_key=None, logger=None, loglevel=log.loglevel_DEFAULT):
         """\
@@ -362,6 +367,7 @@ class X2goRevFwTunnelToSFTP(rforward.X2goRevFwTunnel):
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: int
+
         """
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -382,7 +388,6 @@ class X2goRevFwTunnelToSFTP(rforward.X2goRevFwTunnel):
         self.daemon = True
         self._accept_channels = True
 
-
     def run(self):
         """\
         This method gets run once an L{X2goRevFwTunnelToSFTP} has been started with its
@@ -401,6 +406,7 @@ class X2goRevFwTunnelToSFTP(rforward.X2goRevFwTunnel):
         The channel will last till the connection gets dropped on the X2go server side or 
         until the tunnel gets paused by an L{X2goRevFwTunnelToSFTP.pause()} call or 
         stopped via the C{X2goRevFwTunnelToSFTP.stop_thread()} method.
+
         """
         self._requested_port = self.ssh_transport.request_port_forward('', self.server_port, handler=rforward.x2go_transport_tcp_handler)
         self._keepalive = True
@@ -431,7 +437,6 @@ class X2goRevFwTunnelToSFTP(rforward.X2goRevFwTunnel):
                 self.open_channels['[%s]:%s' % _chan.origin_addr] = _new_chan_thread
 
 
-
 def x2go_rev_forward_sftpchannel_handler(chan=None, auth_key=None, logger=None):
     """\
     Handle incoming sFTP channels that got setup by an L{X2goRevFwTunnelToSFTP} instance.
@@ -453,6 +458,7 @@ def x2go_rev_forward_sftpchannel_handler(chan=None, auth_key=None, logger=None):
     @param logger: you can pass an L{X2goLogger} object to the
         L{X2goProxy} constructor
     @type logger: C{X2goLogger} instance
+
     """
     if logger is None:
         def _dummy_logger(msg, l):
diff --git a/x2go/utils.py b/x2go/utils.py
index 19122cd..0a822ba 100644
--- a/x2go/utils.py
+++ b/x2go/utils.py
@@ -19,23 +19,36 @@
 
 """\
 Python X2go helper functions, constants etc.
+
 """
 __NAME__ = 'x2goutils-pylib'
 
-import sys, os
+import sys
+import os
 import re
+import types
+import copy
 import paramiko
 
+# Python X2go modules
 import defaults
 
+
 def is_in_nx3packmethods(method):
+
     """\
     Test if a given compression method is valid for NX3 Proxy.
+
     """
     return method in defaults._pack_methods_nx3
 
 
 def find_session_line_in_x2golistsessions(session_name, x2go_stdout):
+    """\
+    Return the X2go session meta info as output by x2golistsessions command
+    for session C{session_name}.
+
+    """
     sessions = stdout.read().split("\n")
     for line in sessions:
         # skip empty lines
@@ -47,12 +60,151 @@ def find_session_line_in_x2golistsessions(session_name, x2go_stdout):
 
 
 def slugify(value):
-    """
+    """\
     Normalizes string, converts to lowercase, removes non-alpha characters,
     and converts spaces to hyphens.
+
     """
     import unicodedata
     value = unicodedata.normalize('NFKD', unicode(value)).encode('ascii', 'ignore')
     value = re.sub('[^\w\s-]', '', value).strip().lower()
     return value
 
+def _genSessionProfileId():
+    """\
+    Generate a session profile ID as used in x2goclient's sessions config file.
+    """
+    import datetime
+    return datetime.datetime.utcnow().strftime('%Y%m%d%H%m%S%f')
+
+
+def _checkIniFileDefaults(defaults):
+    """\
+    Check an ini file data structure passed on by a user app or class.
+
+    """
+    if defaults is None:
+        return False
+    if type(defaults) is not types.DictType:
+        return False
+    for sub_dict in defaults.values():
+        if type(sub_dict) is not types.DictType:
+            return False
+    return True
+
+
+def _checkSessionProfileDefaults(defaults):
+    """\
+    Check the data structure of a default session profile passed by a user app.
+
+    """
+    if defaults is None:
+        return False
+    if type(defaults) is not types.DictType:
+        return False
+    return True
+
+
+def _convert_config2params(_config):
+
+        _params = copy.deepcopy(_config)
+
+        _rename_dict = {
+            'host': 'server',
+            'user': 'username',
+            'soundsystem': 'snd_system',
+            'type': 'kbtype',
+            'layout': 'kblayout',
+            'speed': 'link',
+            'sshport': 'port',
+            'export': 'share_local_folders',
+            'print': 'printing',
+            'name': 'profile_name',
+            'key': 'key_filename',
+            'command': 'cmd',
+        }
+        _speed_dict = {
+            '1': 'modem',
+            '2': 'isdn',
+            '3': 'adsl',
+            '4': 'wan',
+            '5': 'lan',
+        }
+
+        for opt, val in _config.iteritems():
+
+            # rename options if necessary
+            if opt in _rename_dict.keys():
+                del _params[opt]
+                opt = _rename_dict[opt]
+            _params[opt] = val
+
+            # translate integer values for connection speed to readable strings
+            if opt == 'link':
+                val = str(val).lower()
+                if val in _speed_dict.keys():
+                    val = _speed_dict[val]
+                val = val.lower()
+                _params['link'] = val
+
+            # share_local_folders is a list
+            if opt == 'share_local_folders':
+                if type(val) is types.StringType:
+                    if val:
+                        _params[opt] = _params[opt].split(',')
+                    else:
+                        _params[opt] = []
+                    #del _params['export']
+                    if not _config['fstunnel']:
+                        _params[opt] = None
+
+            if not val:
+                val = None
+
+        # append value for quality to value for pack method
+        if _params['quality']:
+            _params['pack'] = '%s-%s' % (_params['pack'], _params['quality'])
+            del _params['quality']
+
+        del _params['fstunnel']
+
+        if not _config['fullscreen']:
+            _params['geometry'] = '%sx%s' % (_config['width'], _config['height'])
+        else:
+            _params['geometry'] = 'fullscreen'
+        del _params['width']
+        del _params['height']
+        del _params['fullscreen']
+
+        if not _config['sound']:
+            snd_system = 'none'
+        del _params['sound']
+
+        if _config['rootless']:
+            _params['session_type'] = 'application'
+        else:
+            _params['session_type'] = 'desktop'
+        del _params['rootless']
+
+        # currently ignored in Python X2go, use it for client implementations
+        _ignored_config_options = [
+            'iconvto',
+            'iconvfrom',
+            'useiconv',
+            'dpi',
+            'setdpi',
+            'usekbd',
+            'startsoundsystem',
+            'soundtunnel',
+            'defsndport',
+            'sndport',
+            'icon',
+            'applications',
+            'rdpoptions',
+            'rdpserver',
+            'xdmcpserver',
+            'default',
+        ]
+        for i in _ignored_config_options:
+            del _params[i]
+        return _params
\ No newline at end of file
diff --git a/x2go/exceptions.py b/x2go/x2go_exceptions.py
similarity index 96%
rename from x2go/exceptions.py
rename to x2go/x2go_exceptions.py
index 53452e6..142b2e1 100644
--- a/x2go/exceptions.py
+++ b/x2go/x2go_exceptions.py
@@ -19,6 +19,7 @@
 
 """\
 Python X2go exceptions.
+
 """
 __NAME__ = 'x2goexceptions-pylib'
 
@@ -46,5 +47,4 @@ class X2goSessionException(_X2goException): pass
 class X2goProfileException(_X2goException): pass
 class X2goSettingsException(_X2goException): pass
 class X2goFwTunnelException(_X2goException): pass
-class X2goRevFwTunnelException(_X2goException): pass
-
+class X2goRevFwTunnelException(_X2goException): pass
\ No newline at end of file


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