class NM08ProfileManager(NMProfileManager): """I manage profiles in the system""" def __init__(self): super(NM08ProfileManager, self).__init__() self.helper = GConfHelper() self.gpath = GCONF_PROFILES_BASE # connect to signals self._connect_to_signals() def _init_nm_manager(self): obj = self.bus.get_object(NM08_USER_SETTINGS, NM08_SYSTEM_SETTINGS_OBJ) self.nm_manager = dbus.Interface(obj, NM08_SYSTEM_SETTINGS) def _connect_to_signals(self): self.nm_manager.connect_to_signal("NewConnection", self._on_new_nm_profile, NM08_SYSTEM_SETTINGS) def _on_new_nm_profile(self, opath): obj = self.bus.get_object(NM08_USER_SETTINGS, opath) props = obj.GetSettings(dbus_interface=NM08_SYSTEM_SETTINGS_CONNECTION) # filter out non GSM profiles if props['connection']['type'] == 'gsm': self._add_nm_profile(obj, props) def _add_nm_profile(self, obj, props): uuid = props['connection']['uuid'] assert uuid not in self.nm_profiles, "Adding twice the same profile?" self.nm_profiles[uuid] = obj # handle when a NM profile has been externally added if uuid not in self.profiles: try: profile = self._get_profile_from_nm_connection(uuid) except ex.ProfileNotFoundError: log.msg("Removing non existing NM profile %s" % uuid) del self.nm_profiles[uuid] else: self.profiles[uuid] = profile self.NewConnection(profile.opath) def _get_next_free_gpath(self): """Returns the next unused slot of /system/networking/connections""" all_dirs = list(self.helper.client.all_dirs(self.gpath)) try: max_index = max(map(int, [d.split('/')[-1] for d in all_dirs])) except ValueError: # /system/networking/connections is empty max_index = -1 index = 0 if not all_dirs else max_index + 1 return os.path.join(self.gpath, str(index)) def _get_profile_from_nm_connection(self, uuid): for gpath in self.helper.client.all_dirs(self.gpath): # filter out wlan connections if self.helper.client.dir_exists(os.path.join(gpath, 'gsm')): path = os.path.join(gpath, 'connection', 'uuid') value = self.helper.client.get(path) if value and uuid == self.helper.get_value(value): return self._get_profile_from_gconf_path(gpath) msg = "NM profile identified by uuid %s could not be found" raise ex.ProfileNotFoundError(msg % uuid) def _get_profile_from_gconf_path(self, gconf_path): props = defaultdict(dict) for path in self.helper.client.all_dirs(gconf_path): for entry in self.helper.client.all_entries(path): section, key = entry.get_key().split('/')[-2:] value = entry.get_value() if value is not None: props[section][key] = self.helper.get_value(value) props = transpose_from_NM(props) uuid = props['connection']['uuid'] try: return NM08Profile(self.get_next_dbus_opath(), self.nm_profiles[uuid], gconf_path, props, self) except KeyError: raise ex.ProfileNotFoundError("Profile '%s' could not " "be found" % uuid) def _do_set_profile(self, path, props): props = transpose_to_NM(props) for key in props: for name in props[key]: value = props[key][name] _path = os.path.join(path, key, name) self.helper.set_value(_path, value) self.helper.client.notify(path) self.helper.client.suggest_sync() def add_profile(self, props): """Adds a profile with settings ``props``""" gconf_path = self._get_next_free_gpath() self._do_set_profile(gconf_path, props) # the rest will be handled by _on_new_nm_profile def get_profiles(self): """Returns all the profiles in the system""" if not self.nm_profiles: # cache existing profiles map(self._on_new_nm_profile, self.nm_manager.ListConnections()) if not self.profiles: for path in self.helper.client.all_dirs(self.gpath): # filter out wlan connections if self.helper.client.dir_exists(os.path.join(path, 'gsm')): # profile = self._get_profile_from_gconf_path(path) # uuid = profile.get_settings()['connection']['uuid'] # self.profiles[uuid] = profile try: profile = self._get_profile_from_gconf_path(path) uuid = profile.get_settings()['connection']['uuid'] self.profiles[uuid] = profile except ex.ProfileNotFoundError: pass return self.profiles.values() def remove_profile(self, profile): """Removes profile ``profile``""" uuid = profile.get_settings()['connection']['uuid'] assert uuid in self.profiles, "Removing a non-existent profile?" self.profiles[uuid].remove() del self.profiles[uuid] # as NetworkManager listens for GConf-DBus signals, we don't need # to manually sync it if uuid in self.nm_profiles: del self.nm_profiles[uuid] def update_profile(self, profile, props): """Updates ``profile`` with settings ``props``""" uuid = profile.get_settings()['connection']['uuid'] assert uuid in self.profiles, "Updating a non-existent profile?" _profile = self.profiles[uuid] _profile.update(props) props = transpose_to_NM(props, new=False) if uuid in self.nm_profiles: obj = self.nm_profiles[uuid] obj.Update(props, dbus_interface=NM08_SYSTEM_SETTINGS_CONNECTION)
class NM08Profile(NMProfile): def __init__(self, opath, nm_obj, gpath, props, manager): super(NM08Profile, self).__init__(opath, nm_obj, props, manager) self.helper = GConfHelper() self.gpath = gpath from wader.common.backends import get_backend keyring = get_backend().get_keyring() self.secrets = ProfileSecrets(self, keyring) self._connect_to_signals() def _on_removed(self): log.msg("Profile %s has been removed externally" % self.opath) self.manager.remove_profile(self) def _on_updated(self, props): log.msg("Profile %s has been updated" % self.opath) self.update(props) def _write(self, props): self.props = props props = transpose_to_NM(props) for key, value in props.iteritems(): new_path = os.path.join(self.gpath, key) self.helper.set_value(new_path, value) self.helper.client.notify(self.gpath) self.helper.client.suggest_sync() def _load_info(self): props = {} if self.helper.client.dir_exists(self.gpath): self._load_dir(self.gpath, props) self.props = transpose_from_NM(props) def _load_dir(self, directory, info): for entry in self.helper.client.all_entries(directory): key = os.path.basename(entry.key) info[key] = self.helper.get_value(entry.value) for _dir in self.helper.client.all_dirs(directory): dirname = os.path.basename(_dir) info[dirname] = {} self._load_dir(_dir, info[dirname]) def update(self, props): """Updates the profile with settings ``props``""" self._write(props) self._load_info() self.Updated(patch_list_signature(self.props)) def remove(self): """Removes the profile""" from gconf import UNSET_INCLUDING_SCHEMA_NAMES self.helper.client.recursive_unset(self.gpath, UNSET_INCLUDING_SCHEMA_NAMES) # emit Removed and unexport from DBus self.Removed() self.remove_from_connection()