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

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


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