X2Go dev team | 19 Nov 22:39 2012

python-x2go.git - master (branch) updated: 0.2.0.10-82-g8d835dc

The branch, master has been updated
       via  8d835dcdec07d7f620a25cbcd4aafd88a1a044c7 (commit)
      from  19142c8cf8165b553780cfc33048df5ae11890ef (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 8d835dcdec07d7f620a25cbcd4aafd88a1a044c7
Author: Mike Gabriel <mike.gabriel@...>
Date:   Mon Nov 19 22:37:19 2012 +0100

    Implement functionality for restoring mounted shares on session resumption / re-start. Sponsored by
Dick Kniep, LinDix NL.

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

Summary of changes:
 debian/changelog                |    2 +
 x2go/backends/profiles/_file.py |   42 ++++++++++++--
 x2go/cache.py                   |    1 +
 x2go/client.py                  |   36 +++++++++++-
 x2go/defaults.py                |    2 +-
 x2go/registry.py                |   10 ++++
 x2go/session.py                 |  121 +++++++++++++++++++++++++++++----------
 x2go/utils.py                   |    1 +
 8 files changed, 178 insertions(+), 37 deletions(-)

The diff of changes is:
diff --git a/debian/changelog b/debian/changelog
index 3cd247b..871adcb 100644
--- a/debian/changelog
+++ b/debian/changelog
 <at>  <at>  -48,6 +48,8  <at>  <at>  python-x2go (0.2.1.0-0~x2go1) UNRELEASED; urgency=low
       get_published_applications() of control sessions.
     - Implement some internal locking for X2goSession objects.
     - Add option to disable auto-registration of pubapp sessions.
+    - Implement functionality for restoring mounted shares on session
+      resumption / re-start. Sponsored by Dick Kniep, LinDix NL.
   * /debian/rules:
     + Allow package build on systems with missing dh_python2.
   * /debian/control:
diff --git a/x2go/backends/profiles/_file.py b/x2go/backends/profiles/_file.py
index 586f262..24c2912 100644
--- a/x2go/backends/profiles/_file.py
+++ b/x2go/backends/profiles/_file.py
 <at>  <at>  -28,6 +28,7  <at>  <at>  __NAME__ = 'x2gosessionprofiles-pylib'

 import copy
 import types
+import re

 # Python X2Go modules
 from x2go.defaults import X2GO_SESSIONPROFILES_CONFIGFILES as _X2GO_SESSIONPROFILES_CONFIGFILES
 <at>  <at>  -177,12 +178,14  <at>  <at>  class X2goSessionProfilesFILE(inifiles.X2goIniFile):
         # we have to handle the get_type method separately...
         return self.get_profile_option_type(key)

-    def get_profile_config(self, profile_id_or_name=None, profile_id=None):
+    def get_profile_config(self, profile_id_or_name=None, parameter=None, profile_id=None):
         """\
         The configuration options for a single session profile.

          <at> param profile_id_or_name: either profile ID or profile name is accepted
          <at> type profile_id_or_name: C{str}
+         <at> param parameter: if specified, only the value for the given parameter is returned
+         <at> type parameter: C{str}
          <at> param profile_id: profile ID (fast than specifying C{profile_id_or_name})
          <at> type profile_id: C{str}

 <at>  <at>  -194,6 +197,27  <at>  <at>  class X2goSessionProfilesFILE(inifiles.X2goIniFile):
         _profile_config = {}
         for option in self.iniConfig.options(_profile_id):
             _profile_config[option] = self.get(_profile_id, option, key_type=self.get_profile_option_type(option))
+
+        if parameter is not None:
+            if parameter in _profile_config.keys():
+
+                value = _profile_config[parameter]
+
+                if parameter == 'export':
+                    _strvalue = value.replace(',', ';').strip().strip('"').strip().strip(';').strip()
+                    value = {}
+                    if _strvalue:
+                        _export_paths = _strvalue.split(';')
+                        for _path in _export_paths:
+                            if not re.match('.*:(0|1)$', _path): _path = '%s:1' % _path
+                            _auto_export_path = re.match('.*:1$', _path) and True or False
+                            _export_path = ':'.join(_path.split(':')[:-1])
+                            value[_export_path] = _auto_export_path
+
+                return value
+
+            else:
+                raise X2goProfileException('no such session profile parameter: %s' % parameter)
         return _profile_config

     def default_profile_config(self):
 <at>  <at>  -362,17 +386,27  <at>  <at>  class X2goSessionProfilesFILE(inifiles.X2goIniFile):
          <at> type value: any type, depends on the session profile option

         """
-        profile_id = section
+        profile_id = self.check_profile_id_or_name(section)
         if key == 'name':
             profile_name = value
-            current_profile_name = self.get_value(section, key)
+            current_profile_name = self.get_value(profile_id, key)
             if not profile_name:
                 raise X2goProfileException('profile name for profile id %s may not be empty' % profile_id)
             else:
                 if profile_name != current_profile_name and profile_name in self.profile_names:
                     raise X2goProfileException('a profile of name ,,%s'' already exists' % profile_name)
             self._cached_profile_names = []
-        inifiles.X2goIniFile.update_value(self, section, key, value)
+
+        if key == 'export' and type(value) == types.DictType:
+
+            _strvalue = '"'
+            for folder in value.keys():
+                _strvalue += "%s:%s;" % (folder, int(value[folder]))
+            _strvalue += '"'
+            _strvalue = _strvalue.replace('""', '')
+            value = _strvalue
+
+        inifiles.X2goIniFile.update_value(self, profile_id, key, value)

     def check_profile_id_or_name(self, profile_id_or_name):
         """\
diff --git a/x2go/cache.py b/x2go/cache.py
index 5d90191..7c73692 100644
--- a/x2go/cache.py
+++ b/x2go/cache.py
 <at>  <at>  -149,6 +149,7  <at>  <at>  class X2goListSessionsCache(object):
          <at> raise X2goControlSessionException: if the control session's C{list_mounts} method fails
         """
         try:
+            self.x2go_listsessions_cache[profile_name]['mounts'] = {}
             if self.x2go_listsessions_cache[profile_name]['sessions']:
                 for session_name in self.x2go_listsessions_cache[profile_name]['sessions']:
                     self.x2go_listsessions_cache[profile_name]['mounts'].update(control_session.list_mounts(session_name))
diff --git a/x2go/client.py b/x2go/client.py
index 1dd219b..142e970 100644
--- a/x2go/client.py
+++ b/x2go/client.py
 <at>  <at>  -1919,6 +1919,13  <at>  <at>  class X2goClient(object):
         Get a list of local folders mounted within X2Go session with session hash <session_uuid>
         from this client.

+         <at> param session_uuid: the X2Go session's UUID registry hash
+         <at> type session_uuid: C{str}
+         <at> param profile_name: alternatively, the profile name can be used to get mounted folders of a session
connected profile
+         <at> type profile_name: C{str}
+         <at> param check_list_mounts: query the server-side mount list for up-to-date information
+         <at> type check_list_mounts: C{bool}
+
          <at> return: returns a C{list} of those local folder names that are mounted within X2Go session <session_uuid>.
          <at> rtype: C{list}

 <at>  <at>  -2710,7 +2717,7  <at>  <at>  class X2goClient(object):
     ### Session profile oriented methods
     ### 

-    def get_profile_config(self, profile_id_or_name):
+    def get_profile_config(self, profile_id_or_name, parameter=None):
         """\
         Returns a dictionary with session options and values that represent
         the session profile for C{profile_id_or_name}.
 <at>  <at>  -2718,15 +2725,38  <at>  <at>  class X2goClient(object):
          <at> param profile_id_or_name: name or id of an X2Go session profile as found
             in the sessions configuration file
          <at> type profile_id_or_name: C{str}
+         <at> param parameter: if specified, only the value for the given parameter is returned
+         <at> type parameter: C{str}

          <at> return: a Python dictionary with session profile options
-         <at> rtype: C{dict}
+         <at> rtype: C{dict} or C{bool}, C{int}, C{str}

         """
-        return self.session_profiles.get_profile_config(profile_id_or_name)
+        return self.session_profiles.get_profile_config(profile_id_or_name, parameter=parameter)
     __get_profile_config = get_profile_config
     with_profile_config = get_profile_config

+    def set_profile_config(self, profile_id_or_name, parameter, value):
+        """\
+        Set individual session profile parameters for session profile C{profile_id_or_name}.
+
+         <at> param profile_id_or_name: name or id of an X2Go session profile as found
+            in the sessions configuration file
+         <at> type profile_id_or_name: C{str}
+         <at> param parameter: set this parameter with the given C{value}
+         <at> type parameter: C{str}
+         <at> param value: set this value for the given C{parameter}
+         <at> type value: C{bool}, C{int}, C{str}, C{list} or C{dict}
+
+         <at> return: returns C{True} if this operation has been successful
+         <at> rtype: C{dict}
+
+        """
+        self.session_profiles.update_value(profile_id_or_name, parameter, value)
+        self.session_profiles.write_user_config = True
+        self.session_profiles.write()
+    __set_profile_config = set_profile_config
+
     def to_profile_id(self, profile_name):
         """\
         Retrieve the session profile ID of the session whose profile name
diff --git a/x2go/defaults.py b/x2go/defaults.py
index b158bb2..58a0615 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
 <at>  <at>  -297,7 +297,7  <at>  <at>  X2GO_SESSIONPROFILE_DEFAULTS = {
     'iconvto': 'UTF-8', 'iconvfrom': 'UTF-8', 'useiconv': False,
     'usesshproxy': False, 'sshproxyhost': 'proxyhost.mydomain', 'sshproxyport': 22, 'sshproxyuser':
'', 'sshproxytunnel': 'localhost:44444:server.mydomain.private:22', 'sshproxykeyfile': '',
     'sshproxytype': 'SSH', 'sshproxysameuser': False, 'sshproxysamepass': False,
'sshproxyautologin': True,
-    'useexports': True, 'fstunnel': True, 'export': '',
+    'useexports': True, 'restoreexports': False, 'fstunnel': True, 'export': '',
     'usemimebox': False, 'mimeboxextensions': '', 'mimeboxaction': 'OPEN',
     'fullscreen': False,
     'width': 800,'height': 600, 'maxdim': False, 'dpi': 96, 'setdpi': False, 'xinerama': False,
'multidisp': False,
diff --git a/x2go/registry.py b/x2go/registry.py
index e7b6732..5b4d67f 100644
--- a/x2go/registry.py
+++ b/x2go/registry.py
 <at>  <at>  -332,6 +332,11  <at>  <at>  class X2goSessionRegistry(object):
                 # unregister as master session
                 if _profile_name in self.master_sessions.keys():
                     if self.master_sessions[_profile_name] == self(_session_uuid):
+
+                        # save exported folders to session profile config if requested by session profile parameter ,,restoreexports''...
+                        if self.client_instance and self(_session_uuid).restore_shared_local_folders:
+                            self.client_instance.set_profile_config(_profile_name, 'export', self(_session_uuid)._restore_exported_folders)
+
                         self(_session_uuid).unset_master_session()
                         del self.master_sessions[_profile_name]

 <at>  <at>  -344,6 +349,11  <at>  <at>  class X2goSessionRegistry(object):
                 # unregister as master session
                 if _profile_name in self.master_sessions.keys():
                     if self.master_sessions[_profile_name] == self(_session_uuid):
+
+                        # save exported folders to session profile config if requested by session profile parameter ,,restoreexports''...
+                        if self.client_instance and self(_session_uuid).restore_shared_local_folders:
+                            self.client_instance.set_profile_config(_profile_name, 'export', self(_session_uuid)._restore_exported_folders)
+
                         self(_session_uuid).unset_master_session()
                         del self.master_sessions[_profile_name]

diff --git a/x2go/session.py b/x2go/session.py
index da67aaf..31d7aea 100644
--- a/x2go/session.py
+++ b/x2go/session.py
 <at>  <at>  -89,7 +89,7  <at>  <at>  _X2GO_SESSION_PARAMS = ('use_sshproxy', 'sshproxy_reuse_authinfo',
                         'auto_start_or_resume', 'auto_connect',
                         'printing', 'allow_mimebox',
                         'mimebox_extensions', 'mimebox_action',
-                        'allow_share_local_folders', 'share_local_folders',
+                        'allow_share_local_folders', 'share_local_folders', 'restore_shared_local_folders',
                         'control_backend', 'terminal_backend', 'info_backend', 'list_backend', 'proxy_backend',
'settings_backend', 'printing_backend',
                         'client_rootdir', 'sessions_rootdir', 'ssh_rootdir',
                         'keep_controlsession_alive', 'add_to_known_hosts', 'known_hosts', 'forward_sshagent',
 <at>  <at>  -145,6 +145,7  <at>  <at>  class X2goSession(object):
                  mimebox_action='OPEN',
                  allow_share_local_folders=False,
                  share_local_folders=[],
+                 restore_shared_local_folders=False,
                  control_backend=_X2goControlSession,
                  terminal_backend=_X2goTerminalSession,
                  info_backend=_X2goServerSessionInfo,
 <at>  <at>  -194,6 +195,8  <at>  <at>  class X2goSession(object):
          <at> type allow_share_local_folders: C{bool}
          <at> param share_local_folders: list of local folders to share with the remote X2Go session
          <at> type share_local_folders: C{list}
+         <at> param restore_shared_local_folders: store actual list of shared local folders after session has been
suspended or terminated
+         <at> type restore_shared_local_folders: C{bool}
          <at> param control_backend: X2Go control session backend to use
          <at> type control_backend: C{class}
          <at> param terminal_backend: X2Go terminal session backend to use
 <at>  <at>  -276,6 +279,7  <at>  <at>  class X2goSession(object):
         self.printing = printing
         self.allow_share_local_folders = allow_share_local_folders
         self.share_local_folders = share_local_folders
+        self.restore_shared_local_folders = restore_shared_local_folders
         self.allow_mimebox = allow_mimebox
         self.mimebox_extensions = mimebox_extensions
         self.mimebox_action = mimebox_action
 <at>  <at>  -364,6 +368,9  <at>  <at>  class X2goSession(object):
         self._progress_status = 0
         self._lock = threading.Lock()

+        if self.client_instance and self.restore_shared_local_folders:
+            self._restore_exported_folders = self.client_instance.get_profile_config(self.profile_name, 'export')
+
     def get_client_instance(self):
         """\
         Return parent L{X2goClient} instance if avaiable.
 <at>  <at>  -569,9 +576,9  <at>  <at>  class X2goSession(object):
             gevent.sleep(1)

         if wait:
-            gevent.spawn_later(wait, self.share_all_local_folders)
+            gevent.spawn_later(wait, self.share_all_local_folders, update_exported_folders=False)
         else:
-            gevent.spawn(self.share_all_local_folders)
+            gevent.spawn(self.share_all_local_folders, update_exported_folders=False)
     __set_master_session = set_master_session

     def unset_master_session(self):
 <at>  <at>  -581,7 +588,7  <at>  <at>  class X2goSession(object):
         """
         # unmount shared folders
         if self.has_terminal_session():
-            self.unshare_all_local_folders()
+            self.unshare_all_local_folders(update_exported_folders=False)
         self.master_session = False
     __unset_master_session = unset_master_session

 <at>  <at>  -719,6 +726,10  <at>  <at>  class X2goSession(object):
             del params['share_local_folders'] 
         except KeyError: pass
         try:
+            self.restore_shared_local_folders = params['restore_shared_local_folders']
+            del params['restore_shared_local_folders']
+        except KeyError: pass
+        try:
             self.allow_mimebox = params['allow_mimebox']
             del params['allow_mimebox']
         except KeyError: pass
 <at>  <at>  -1290,6 +1301,7  <at>  <at>  class X2goSession(object):
         self.terminated = None
         self.faults = None
         self.active = False
+        self._lock.release()
         self.unset_master_session()
         try:
             self.update_status(force_update=True)
 <at>  <at>  -1894,7 +1906,7  <at>  <at>  class X2goSession(object):
                 self._progress_status = 90
                 progress_event.set()

-                # if there is a client instance for X2Go sessions that the client instance will handle the mounting of
shared folders
+                # if self.client_instance exists than the folder sharing is handled via the self.set_master_session()
evoked by the session registry
                 if (not self.client_instance) and \
                    self._SUPPORTED_FOLDERSHARING and \
                    self.allow_share_local_folders:
 <at>  <at>  -2104,6 +2116,10  <at>  <at>  class X2goSession(object):
          <at> raise X2goSessionException: if the session could not be suspended

         """
+        _store_shared_folders = {}
+        for folder in self.shared_folders:
+            _store_shared_folders.update({ folder: True })
+
         self._lock.acquire()
         try:
             _retval = self._suspend()
 <at>  <at>  -2111,6 +2127,7  <at>  <at>  class X2goSession(object):
             raise
         finally:
             self._lock.release()
+
         return _retval

     def _suspend(self):
 <at>  <at>  -2137,12 +2154,12  <at>  <at>  class X2goSession(object):

                 self.unset_master_session()

-                if self.terminal_session.suspend():
-
-                    self.session_cleanup()
-                    del self.terminal_session
-                    self.terminal_session = None
-                    return True
+                if self.has_terminal_session():
+                    if self.terminal_session.suspend():
+                        self.session_cleanup()
+                        del self.terminal_session
+                        self.terminal_session = None
+                        return True

             elif self.has_control_session() and self.session_name:
                 if self.control_session.suspend(session_name=self.session_name):
 <at>  <at>  -2181,6 +2198,7  <at>  <at>  class X2goSession(object):
             raise
         finally:
             self._lock.release()
+
         return _retval

     def _terminate(self):
 <at>  <at>  -2207,11 +2225,12  <at>  <at>  class X2goSession(object):

                 self.unset_master_session()

-                if self.terminal_session.terminate():
-                    self.session_cleanup()
-                    del self.terminal_session
-                    self.terminal_session = None
-                    return True
+                if self.has_terminal_session():
+                    if self.terminal_session.terminate():
+                        self.session_cleanup()
+                        del self.terminal_session
+                        self.terminal_session = None
+                        return True

             elif self.has_control_session() and self.session_name:
                 if self.control_session.terminate(session_name=self.session_name):
 <at>  <at>  -2397,7 +2416,19  <at>  <at>  class X2goSession(object):
         return False
     __is_folder_sharing_available = is_folder_sharing_available

-    def share_local_folder(self, local_path=None, folder_name=None):
+    def _update_restore_exported_folders(self):
+
+        # remember exported folders for restoring them on session suspension/termination
+        if self.client_instance and self.restore_shared_local_folders:
+            _exported_folders = self.client_instance.get_profile_config(self.profile_name, 'export')
+            for folder in self.shared_folders:
+                _exported_folders.update({ unicode(folder): True })
+            for folder in _exported_folders.keys():
+                if (folder not in self.shared_folders) and _exported_folders[folder]:
+                    del _exported_folders[folder]
+            self._restore_exported_folders = _exported_folders
+
+    def share_local_folder(self, local_path=None, folder_name=None, update_exported_folders=True):
         """\
         Share a local folder with this registered X2Go session.

 <at>  <at>  -2406,6 +2437,8  <at>  <at>  class X2goSession(object):
          <at> type local_path: C{str}
          <at> param folder_name: synonymous to C{local_path}
          <at> type folder_name: C{str}
+         <at> param update_exported_folders: do an update of the session profile option ,,export'' after the operation
+         <at> type update_exported_folders: C{bool}

          <at> return: returns C{True} if the local folder has been successfully mounted within
             this X2Go session
 <at>  <at>  -2419,18 +2452,26  <at>  <at>  class X2goSession(object):

         if self.has_terminal_session():
             if self.is_folder_sharing_available() and self.is_master_session():
+                # append local_path to list of shared folders before mounting
+                self.shared_folders.append(local_path)
                 if self.terminal_session.share_local_folder(local_path=local_path):
-                    self.shared_folders.append(local_path)
+                    if update_exported_folders:
+                        self._update_restore_exported_folders()
                     return True
+                # if we failed remove the local_path element again...
+                self.shared_folders.remove(local_path)
                 return False
         else:
             raise x2go_exceptions.X2goSessionException('this X2goSession object does not have any associated terminal')
     __share_local_folder = share_local_folder

-    def share_all_local_folders(self):
+    def share_all_local_folders(self, update_exported_folders=True):
         """\
         Share all local folders configured to be mounted within this X2Go session.

+         <at> param update_exported_folders: do an update of the session profile option ,,export'' after the operation
+         <at> type update_exported_folders: C{bool}
+
          <at> return: returns C{True} if all local folders could be successfully mounted
             inside this X2Go session
          <at> rtype: C{bool}
 <at>  <at>  -2444,21 +2485,26  <at>  <at>  class X2goSession(object):
                         _retval = True
                         for _folder in self.share_local_folders:
                             try:
-                                _retval = self.share_local_folder(_folder) and _retval
+                                _retval = self.share_local_folder(_folder, update_exported_folders=False) and _retval
                             except x2go_exceptions.X2goUserException, e:
                                 self.logger('%s' % str(e), loglevel=log.loglevel_WARN)
+                        if update_exported_folders:
+                            self._update_restore_exported_folders()
+
                 else:
                     self.HOOK_foldersharing_not_available()
         return _retval
     __share_all_local_folders = share_all_local_folders

-    def unshare_all_local_folders(self, force_all=False):
+    def unshare_all_local_folders(self, force_all=False, update_exported_folders=True):
         """\
         Unshare all local folders mounted within this X2Go session.

          <at> param force_all: Really unmount _all_ shared folders, including the print spool folder and
             the MIME box spool dir (not recommended).
          <at> type force_all: C{bool}
+         <at> param update_exported_folders: do an update of the session profile option ,,export'' after the operation
+         <at> type update_exported_folders: C{bool}

          <at> return: returns C{True} if all local folders could be successfully unmounted
             inside this X2Go session
 <at>  <at>  -2471,19 +2517,23  <at>  <at>  class X2goSession(object):
             if self.is_folder_sharing_available() and self.is_master_session():
                 if force_all:
                     self.shared_folders = []
-                    return self.terminal_session.unshare_all_local_folders()
+                    retval = self.terminal_session.unshare_all_local_folders()
+                    return retval
                 else:
+                    _shared_folders = copy.deepcopy(self.shared_folders)
+                    self.shared_folders = []
                     retval = 0
-                    for _shared_folder in self.shared_folders:
+                    for _shared_folder in _shared_folders:
                         retval = retval | self.terminal_session.unshare_local_folder(_shared_folder)
-                    self.shared_folders = []
+                    if update_exported_folders:
+                        self._update_restore_exported_folders()
                     return retval
         else:
             raise x2go_exceptions.X2goSessionException('this X2goSession object does not have any associated terminal')
         return False
     __unshare_all_local_folders = unshare_all_local_folders

-    def unshare_local_folder(self, local_path=None):
+    def unshare_local_folder(self, local_path=None, update_exported_folders=True):
         """\
         Unshare a local folder that is mounted within this X2Go session.

 <at>  <at>  -2491,6 +2541,9  <at>  <at>  class X2goSession(object):
             file system that is mounted in this X2Go session and shall be
             unmounted
          <at> type local_path: C{str}
+         <at> param update_exported_folders: do an update of the session profile option ,,export'' after the operation
+         <at> type update_exported_folders: C{bool}
+
          <at> return: returns C{True} if all local folders could be successfully unmounted
             inside this X2Go session
          <at> rtype: C{bool}
 <at>  <at>  -2500,10 +2553,18  <at>  <at>  class X2goSession(object):
         """
         if self.has_terminal_session():
             if self.is_folder_sharing_available() and self.is_master_session() and local_path in self.shared_folders:
+                # update shared_folders before(!) unmounting...
                 self.shared_folders.remove(local_path)
-                return self.terminal_session.unshare_local_folder(local_path=local_path)
+                _retval = self.terminal_session.unshare_local_folder(local_path=local_path)
+                # unmounting failed? Re-add local_patch to shared_folders for now...
+                if not _retval:
+                    self.shared_folders.append(local_path)
+                if _retval and update_exported_folders:
+                    self._update_restore_exported_folders()
         else:
             raise x2go_exceptions.X2goSessionException('this X2goSession object does not have any associated terminal')
+
+        return _retval
     __unshare_local_folder = unshare_local_folder

     def get_shared_folders(self, check_list_mounts=False, mounts=None):
 <at>  <at>  -2531,21 +2592,22  <at>  <at>  class X2goSession(object):
                 _found = False

                 for mount in mounts:
+                    if _found: continue
                     mount = mount.split('|')[1]
                     if _X2GOCLIENT_OS == 'Windows':
+
                         _driveletter, _path = os.path.splitdrive(shared_folder)
                         _mount_point = '_windrive_%s%s' % (_driveletter[0], _path.replace('\\', '_'))
                         _mount_point = _mount_point.replace(' ', '_')

                         if mount.lower().endswith(_mount_point.lower()):
                             _found = True
-                            break
+
                     else:
                         _mount_point = shared_folder.replace('/', '_')
                         _mount_point = _mount_point.replace(' ', '_')
                         if mount.endswith(_mount_point):
                             _found = True
-                            break

                 if not _found:
                     unshared_folders.append(shared_folder)
 <at>  <at>  -2553,11 +2615,12  <at>  <at>  class X2goSession(object):
             for unshared_folder in unshared_folders:
                 try:
                     self.shared_folders.remove(unshared_folder)
+                    self._update_restore_exported_folders()
                     self.logger('Detected server-side unsharing of client-side folder for profile %s: %s:' %
(self.get_profile_name(), shared_folder), loglevel=log.loglevel_INFO)
                 except IndexError:
                     pass

-        return self.shared_folders
+        return [ unicode(s) for s in self.shared_folders ]
     __get_shared_folders = get_shared_folders

     def is_locked(self):
diff --git a/x2go/utils.py b/x2go/utils.py
index 0a25fd3..ab98120 100644
--- a/x2go/utils.py
+++ b/x2go/utils.py
 <at>  <at>  -186,6 +186,7  <at>  <at>  def _convert_SessionProfileOptions_2_SessionParams(options):
             'speed': 'link',
             'sshport': 'port',
             'useexports': 'allow_share_local_folders',
+            'restoreexports': 'restore_shared_local_folders',
             'usemimebox': 'allow_mimebox',
             'mimeboxextensions': 'mimebox_extensions',
             'mimeboxaction': 'mimebox_action',

hooks/post-receive

Gmane