/*************************************************************************** * * knetworkmanager-storage.cpp - A NetworkManager frontend for KDE * * Copyright (C) 2005, 2006 Novell, Inc. * * Author: Helmut Schaa , * Author: Timothy Pearson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * **************************************************************************/ #include #include #include #include #include #include "knetworkmanager-storage.h" #include "knetworkmanager-connection_store.h" #include "knetworkmanager-wireless_connection.h" #include "knetworkmanager-wired_connection.h" #include "knetworkmanager-cdma_connection.h" #include "knetworkmanager-gsm_connection.h" #include "knetworkmanager-vpn_connection.h" #include "knetworkmanager-connection.h" #include "knetworkmanager-connection_setting.h" #include "xmlmarshaller.h" #include "knetworkmanager-connection_setting_info.h" #include "knetworkmanager-connection_setting_wired.h" #include "knetworkmanager-connection_setting_wireless.h" #include "knetworkmanager-connection_setting_wireless_security.h" #include "knetworkmanager-connection_setting_ipv4.h" using namespace ConnectionSettings; static KStaticDeleter sd2; // private stuff class StoragePrivate { public: StoragePrivate() {}; ~StoragePrivate() {}; static Storage* _instance; }; Storage* StoragePrivate::_instance = NULL; Storage* Storage::getInstance() { if (StoragePrivate::_instance) return StoragePrivate::_instance; return sd2.setObject(StoragePrivate::_instance, new Storage()); } Storage::Storage() { d = new StoragePrivate(); // defer the connection init a bit TQTimer::singleShot(0, this, TQT_SLOT(slotInit())); } Storage::~Storage() { delete d; } void Storage::slotInit() { ConnectionStore* cstore = ConnectionStore::getInstance(); // we want to get notified whenever a new connection is created, edited or deleted connect(cstore, TQT_SIGNAL(signalConnectionAdded(ConnectionSettings::Connection*)), this, TQT_SLOT(slotConnectionAdded(ConnectionSettings::Connection*))); connect(cstore, TQT_SIGNAL(signalConnectionRemoved(ConnectionSettings::Connection*)), this, TQT_SLOT(slotConnectionRemoved(ConnectionSettings::Connection*))); } void Storage::slotConnectionAdded(Connection* con) { // connection added, save it saveConnection(con); KGlobal::config()->sync(); } void Storage::slotConnectionRemoved(Connection* con) { // find the appropriate connection and delete it from the storage deleteConnection(con); KGlobal::config()->sync(); } Connection* Storage::createConnectionByType(const TQString& cType) { // TODO: use a factory class here if (cType == NM_SETTING_WIRELESS_SETTING_NAME) return new WirelessConnection(); else if (cType == NM_SETTING_WIRED_SETTING_NAME) return new WiredConnection(); else if(cType == NM_SETTING_CDMA_SETTING_NAME) return new CDMAConnection(); else if(cType == NM_SETTING_GSM_SETTING_NAME) return new GSMConnection(); else if (cType == NM_SETTING_VPN_SETTING_NAME) return new VPNConnection(); else return NULL; } void Storage::restoreConnections() { kdDebug() << k_funcinfo << endl; // let's read all connections from the config-file and add them to the connection-store ConnectionStore* store = ConnectionStore::getInstance(); TQStringList groups = KGlobal::config()->groupList(); const TQStringList::Iterator end = groups.end(); for ( TQStringList::Iterator it = groups.begin(); it != end; ++it ) { if ( !(*it).startsWith( "Connection_" ) ) continue; // restore that connection Connection* conn = NULL; if ( (conn = restoreConnection(*it)) != NULL) { // add the connection to the store store->addConnection(conn); } } } Connection* Storage::restoreConnection(const TQString& grpname) { Connection* conn = NULL; kdDebug() << k_funcinfo << " " << grpname << endl; // we have a connection to restore KConfigGroup grp( KGlobal::config(), grpname); TQString id = grp.readEntry("Id"); TQString cType = grp.readEntry("Type"); // ID is needed! if (id.isEmpty() || cType.isEmpty()) return NULL; // create a new connection object by its type conn = createConnectionByType(cType); // check if the connection was successfully created if (!conn) return NULL; // set the connection ID conn->setID(id); // restore all appropriate settings TQStringList settings = grp.readListEntry("Settings"); for (TQStringList::ConstIterator it = settings.begin(); it != settings.end(); ++it) { if ( !restoreSetting(conn, *it) ) { // setting could not be restored -> Error kdDebug() << " Connection " << id.ascii() << " could not be restored." << endl; kdError() << k_funcinfo << " Connection " << id << " could not be restored." << endl; delete conn; conn = NULL; return NULL; } } // restore all appropriate secrets TQStringList secrets = grp.readListEntry("Secrets"); for (TQStringList::ConstIterator it = secrets.begin(); it != secrets.end(); ++it) { if ( !restoreSecrets(conn, *it) ) { // setting could not be restored -> Error kdDebug() << " Connection " << id.ascii() << " could not be restored." << endl; kdError() << k_funcinfo << " Connection " << id << " could not be restored." << endl; delete conn; conn = NULL; return NULL; } } return conn; } bool Storage::restoreSetting(Connection* conn, const TQString& setting_grp_name) { kdDebug() << k_funcinfo << " " << setting_grp_name << endl; kdDebug() << "restore setting: " << setting_grp_name.ascii() << endl; KConfigGroup setting_grp(KGlobal::config(), setting_grp_name); TQMap config_map = KGlobal::config()->entryMap(setting_grp_name); TQString type = setting_grp.readEntry("Type"); // get the appropriate setting from the connection ConnectionSetting* setting = conn->getSetting(type); if (!setting) { kdWarning() << k_funcinfo << "Connection " << conn->getID() << ": Setting " << type << " could not be restored" << endl; return false; } // read the SettingsMap from kconfig SettingsMap map; for(TQMap::ConstIterator it = config_map.begin(); it != config_map.end(); ++it) { if (!it.key().startsWith("Value_")) continue; TQString key = it.key(); // get the original name key.replace("Value_", ""); TQString xmldata = it.data(); TQT_DBusData dbusdata = XMLMarshaller::toTQT_DBusData(xmldata); map.insert(key, dbusdata); } // restore the setting from the generated map setting->fromMap(map); return true; } bool Storage::restoreSecrets(Connection* conn, const TQString& secrets_grp_name) { kdDebug() << k_funcinfo << " " << secrets_grp_name << endl; kdDebug() << "restore secret: " << secrets_grp_name.ascii() << endl; KConfigGroup secrets_grp(KGlobal::config(), secrets_grp_name); TQMap config_map = KGlobal::config()->entryMap(secrets_grp_name); TQString type = secrets_grp.readEntry("Type"); // get the appropriate setting from the connection ConnectionSetting* setting = conn->getSetting(type); if (!setting) { kdWarning() << k_funcinfo << "Connection " << conn->getID() << ": Secrets for setting " << type << " could not be restored" << endl; return false; } // read the SettingsMap from kconfig SettingsMap map; for(TQMap::ConstIterator it = config_map.begin(); it != config_map.end(); ++it) { if (!it.key().startsWith("Value_")) continue; TQString key = it.key(); // get the original name key.replace("Value_", ""); TQString xmldata = it.data(); TQT_DBusData dbusdata = XMLMarshaller::toTQT_DBusData(xmldata); map.insert(key, dbusdata); } // restore the setting from the generated map setting->fromSecretsMap(map); return true; } bool Storage::restoreVPNSecrets(Connection* conn, const TQString& secrets_grp_name) { kdDebug() << k_funcinfo << " " << secrets_grp_name << endl; kdDebug() << "restore secret: " << secrets_grp_name.ascii() << endl; KConfigGroup secrets_grp(KGlobal::config(), secrets_grp_name); TQMap config_map = KGlobal::config()->entryMap(secrets_grp_name); TQString type = secrets_grp.readEntry("Type"); // get the appropriate setting from the connection ConnectionSetting* setting = conn->getSetting(type); if (!setting) { kdWarning() << k_funcinfo << "Connection " << conn->getID() << ": Secrets for setting " << type << " could not be restored" << endl; return false; } // read the SettingsMap from kconfig SettingsMap map; for(TQMap::ConstIterator it = config_map.begin(); it != config_map.end(); ++it) { if (!it.key().startsWith("Value_")) continue; TQString key = it.key(); // get the original name key.replace("Value_", ""); TQString xmldata = it.data(); TQT_DBusData dbusdata = XMLMarshaller::toTQT_DBusData(xmldata); map.insert(key, dbusdata); } // restore the setting from the generated map setting->fromSecretsMap(map); return true; } void Storage::saveConnections() { kdDebug() << k_funcinfo << endl; kdDebug() << "Storage::saveConnections" << endl; printf("Storage::saveConnections\n\r"); // write all connections we get from the connection-store to disk ConnectionStore* store = ConnectionStore::getInstance(); TQValueList connections = store->getConnections(); for (TQValueList::ConstIterator it = connections.begin(); it != connections.end(); ++it) { // save this connection saveConnection(*it); } KGlobal::config()->sync(); } bool Storage::saveConnection(Connection* conn) { KConfig* config = KGlobal::config(); TQString id = conn->getID(); TQString cType = conn->getType(); kdDebug() << k_funcinfo << " <" << id << ">" << endl; kdDebug() << "Storage::saveConnection " << id.ascii() << endl; // connections without id are evil if (id.isEmpty() || cType.isEmpty()) return false; // let's get the config group for this connection KConfigGroup grp(config, TQString("Connection_%1").tqarg(id)); TQStringList settings_grps; TQStringList secrets_grps; // save the connections settings to the configfile if (saveConnectionSettings(conn, settings_grps, secrets_grps)) { grp.writeEntry("Type", cType); grp.writeEntry("Id", id); // save the list of settings groups grp.writeEntry("Settings", settings_grps); grp.writeEntry("Secrets", secrets_grps); } return false; } bool Storage::saveConnectionSettings(Connection* conn, TQStringList& settings_grps, TQStringList& secrets_grps) { TQString id = conn->getID(); // connections without id are evil if (id.isEmpty()) return false; // iterate over all settings TQValueList settings = conn->getSettings(); TQString setting_grp; TQString secrets_grp; // save all settings for (TQValueList::ConstIterator it = settings.begin(); it != settings.end(); ++it) { if (!saveConnectionSetting(conn, *it, setting_grp)) return false; if ((*it)->hasSecrets()) { if (!saveConnectionSecrets(conn, *it, secrets_grp)) return false; secrets_grps.append(secrets_grp); } settings_grps.append(setting_grp); } return true; } bool Storage::saveConnectionSetting(Connection* conn, ConnectionSetting* setting, TQString& setting_grp) { KConfig* config = KGlobal::config(); TQString id = conn->getID(); TQString type = setting->getType(); kdDebug() << k_funcinfo << " <" << id << "> <" << type << ">" << endl; // ID is necessary if (id.isEmpty()) return false; // get a group for this setting setting_grp = TQString("ConnectionSetting_%1_%2").tqarg(id).tqarg(type); KConfigGroup grp(config, setting_grp); // write the type grp.writeEntry("Type", type); // write the values SettingsMap map = setting->toMap(); for (SettingsMap::ConstIterator it = map.begin(); it != map.end(); ++it) { kdDebug() << k_funcinfo << " " << TQString("Value_%1").tqarg(it.key()) << " = " << XMLMarshaller::fromTQT_DBusData( it.data() )<< endl; grp.writeEntry(TQString("Value_%1").tqarg(it.key()), XMLMarshaller::fromTQT_DBusData( it.data() )); } return true; } bool Storage::saveConnectionSecrets(Connection* conn, ConnectionSetting* setting, TQString& setting_grp) { KConfig* config = KGlobal::config(); TQString id = conn->getID(); TQString type = setting->getType(); bool storage_requested; kdDebug() << k_funcinfo << " <" << id << "> <" << type << ">" << endl; // ID is necessary if (id.isEmpty()) return false; // see if permanent storage was requested by the user SettingsMap setting_map = setting->toMap(); storage_requested = true; for (SettingsMap::ConstIterator it = setting_map.begin(); it != setting_map.end(); ++it) { if (it.key() == "Commit to disk") { if (XMLMarshaller::fromTQT_DBusData(it.data()) == TQString("true")) { storage_requested = true; } if (XMLMarshaller::fromTQT_DBusData(it.data()) == TQString("false")) { storage_requested = false; } } } printf("Secrets storage requested: %d\n\r", storage_requested); // get a group for this setting setting_grp = TQString("ConnectionSecrets_%1_%2").tqarg(id).tqarg(type); KConfigGroup grp(config, setting_grp); // write the type grp.writeEntry("Type", type); // write the values SettingsMap map = setting->toSecretsMap(false); for (SettingsMap::ConstIterator it = map.begin(); it != map.end(); ++it) { kdDebug() << k_funcinfo << " " << TQString("Value_%1").tqarg(it.key()) << " = " << XMLMarshaller::fromTQT_DBusData( it.data() )<< endl; if (storage_requested == true) { grp.writeEntry(TQString("Value_%1").tqarg(it.key()), XMLMarshaller::fromTQT_DBusData( it.data() )); } else { grp.writeEntry(TQString("Value_%1").tqarg(it.key()), TQString("") ); } } return true; } bool Storage::hasSecretsStored(Connection* connection) { TQString id = connection->getID(); // ID is necessary if (id.isEmpty()) return false; TQValueList settings = connection->getSettings(); for (TQValueList::Iterator it = settings.begin(); it != settings.end(); ++it) { if (hasSecretsStored(connection, *it)) return true; } return false; } bool Storage::hasSecretsStored(Connection* connection, ConnectionSetting* setting) { TQString id = connection->getID(); TQString type = setting->getType(); kdDebug() << "Storage::hasSecretsStored" << endl; // ID is necessary if (id.isEmpty()) return false; // get a group for this setting TQString setting_grp_name = TQString("ConnectionSecrets_%1_%2").tqarg(id).tqarg(type); TQMap config_map = KGlobal::config()->entryMap(setting_grp_name); return !(config_map.isEmpty()); } bool Storage::restoreAllSecrets(Connection* connection) { TQString id = connection->getID(); bool retval = true; if (id.isEmpty()) return false; TQValueList settings = connection->getSettings(); for (TQValueList::Iterator it = settings.begin(); it != settings.end(); ++it) { if (hasSecretsStored(connection, *it)) if (!restoreSecrets(connection, *it)) retval = false; } return retval; } bool Storage::restoreSecrets(Connection* connection, ConnectionSetting* setting) { TQString id = connection->getID(); TQString type = setting->getType(); kdDebug() << "Storage::restoreSecrets" << endl; // ID is necessary if (id.isEmpty()) return false; // get a group for this setting TQString setting_grp = TQString("ConnectionSecrets_%1_%2").tqarg(id).tqarg(type); // restore the setting return restoreSecrets(connection, setting_grp); } bool Storage::restoreVPNSecrets(Connection* connection, ConnectionSetting* setting) { TQString id = connection->getID(); TQString type = setting->getType(); printf("Storage::restoreVPNSecrets\n\r"); kdDebug() << "Storage::restoreVPNSecrets" << endl; // ID is necessary if (id.isEmpty()) return false; // get a group for this setting TQString setting_grp = TQString("ConnectionSecrets_%1_%2").tqarg(id).tqarg(type); // restore the setting return restoreVPNSecrets(connection, setting_grp); } bool Storage::deleteConnection(Connection* conn) { KConfig* config = KGlobal::config(); TQString id = conn->getID(); TQString cType = conn->getType(); kdDebug() << k_funcinfo << " <" << id << ">" << endl; kdDebug() << "Storage::deleteConnection " << id.ascii() << endl; // connections without id are evil if (id.isEmpty() || cType.isEmpty()) return false; // let's get the config group for this connection KConfigGroup grp(config, TQString("Connection_%1").tqarg(id)); // delete all associated settings TQStringList settings = grp.readListEntry("Settings"); for (TQStringList::ConstIterator it = settings.begin(); it != settings.end(); ++it) { KConfigGroup setting(config, *it); setting.deleteGroup(); } // delete all associated secrets TQStringList secrets = grp.readListEntry("Secrets"); for (TQStringList::ConstIterator it = secrets.begin(); it != secrets.end(); ++it) { KConfigGroup setting(config, *it); setting.deleteGroup(); } grp.deleteGroup(); return true; } #include "knetworkmanager-storage.moc"