diff options
author | Timothy Pearson <[email protected]> | 2013-02-01 17:25:31 -0600 |
---|---|---|
committer | Timothy Pearson <[email protected]> | 2013-02-01 17:25:31 -0600 |
commit | 3c66b171a6f0ad667c538fd727bbcef54af71d37 (patch) | |
tree | ae80c2d1cb16b92fb7d5a73bbe5ce34fbc5ae016 /kiostdetool/kioskrun.cpp | |
parent | 867b7c23aa5ee22368683f23635ded9506587069 (diff) | |
download | kiosktool-3c66b171a6f0ad667c538fd727bbcef54af71d37.tar.gz kiosktool-3c66b171a6f0ad667c538fd727bbcef54af71d37.zip |
Fix FTBFS
Diffstat (limited to 'kiostdetool/kioskrun.cpp')
-rw-r--r-- | kiostdetool/kioskrun.cpp | 1687 |
1 files changed, 1687 insertions, 0 deletions
diff --git a/kiostdetool/kioskrun.cpp b/kiostdetool/kioskrun.cpp new file mode 100644 index 0000000..f5693ca --- /dev/null +++ b/kiostdetool/kioskrun.cpp @@ -0,0 +1,1687 @@ +/* + * kioskrun.cpp + * + * Copyright (C) 2004 Waldo Bastian <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 "kioskrun.h" + +#include "config.h" + +#include <assert.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <tqdir.h> +#include <tqfile.h> + +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <tdeconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <ksavefile.h> +#include <ksimpleconfig.h> +#include <kstandarddirs.h> +#include <kurl.h> +#include <kuser.h> + +#include "kiosksync.h" + +#include <tdeio/netaccess.h> +#define NETACCESS TDEIO::NetAccess + +#undef DEBUG_ENTRIES + +KioskRun *KioskRun::s_self = 0; + +KioskRun::KioskRun( TQObject* parent, const char* name) + : TQObject(parent, name), m_dcopClient(0), m_instance(0), m_localKdercConfig(0) +{ + m_noRestrictions = false; + m_forceSycocaUpdate = false; + s_self = this; + m_saveConfigCache.setAutoDelete(true); + m_immutableStatusCache.setAutoDelete(true); + m_homeDir = TQDir::homeDirPath()+"/.trinity-test"; + TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(); + m_kderc = TQFile::decodeName(args->getOption("kderc")); + m_isRoot = (getuid() == 0); +} + +KioskRun::~KioskRun() +{ + shutdownRuntimeEnv(); + s_self = 0; +} + +void +KioskRun::setUser(const TQString &user) +{ + if (m_user == user) return; + + shutdownRuntimeEnv(); + shutdownConfigEnv(); + m_user = user; +} + +static void filterDupes(TQStringList &list) +{ + TQStringList tmp; + for(TQStringList::ConstIterator it = list.begin(); + it != list.end(); ++it) + { + if (!tmp.contains(*it)) + tmp.append(*it); + } + list = tmp; +} + +void +KioskRun::setKdeDirs(const TQStringList &dirs) +{ + if (m_kdeDirs == dirs) return; + + shutdownRuntimeEnv(); + shutdownConfigEnv(); + m_kdeDirs = dirs; + TQStringList xdgDataDirs = TQStringList::split(':', TQFile::decodeName(getenv("XDG_DATA_DIRS"))); + if (xdgDataDirs.isEmpty()) + { + xdgDataDirs = TQStringList::split(':', TDEGlobal::dirs()->kfsstnd_prefixes()); + xdgDataDirs.pop_front(); + for(TQStringList::Iterator it = xdgDataDirs.begin(); + it != xdgDataDirs.end(); ++it) + { + *it += "share"; + } + xdgDataDirs << "/usr/local/share" << "/usr/share"; + } + + m_xdgDataDirs.clear(); + for(TQStringList::ConstIterator it = dirs.begin(); + it != dirs.end(); ++it) + { + m_xdgDataDirs.append(*it+"/share"); + } + m_xdgDataDirs += xdgDataDirs; + filterDupes(m_xdgDataDirs); + + TQStringList xdgConfigDirs = TQStringList::split(':', TQFile::decodeName(getenv("XDG_CONFIG_DIRS"))); + if (xdgConfigDirs.isEmpty()) + { + xdgConfigDirs << "/etc/xdg"; + TQString sysconfMenuDir = TDEGlobal::dirs()->findDirs("xdgconf-menu", TQString()).last(); + if (sysconfMenuDir.endsWith("/menus/")) + xdgConfigDirs << sysconfMenuDir.left(sysconfMenuDir.length()-7); + + } + + m_xdgConfigDirs.clear(); + for(TQStringList::ConstIterator it = dirs.begin(); + it != dirs.end(); ++it) + { + m_xdgConfigDirs.append(*it+"/etc/xdg"); + } + + m_xdgConfigDirs += xdgConfigDirs; + filterDupes(m_xdgConfigDirs); +} + +void +KioskRun::deleteDir(const TQString &dir) +{ + if (dir.length() <= 1) // Safety + return; + if (!dir.startsWith("/")) // Safety + return; + Q_ASSERT(dir.startsWith(m_homeDir)); + + TDEProcess proc; + proc << "rm" << "-rf" << dir; + proc.start(TDEProcess::Block); +} + +void +KioskRun::applyEnvironment(TDEProcess *p) +{ + p->setEnvironment("HOME", m_homeDir); + p->setEnvironment("TDEHOME", m_homeDir+"/.trinity"); + p->setEnvironment("TDEROOTHOME", m_homeDir+"/.trinity"); + p->setEnvironment("TDEDIRS", m_kdeDirs.join(":")); + p->setEnvironment("XDG_DATA_HOME", m_homeDir+"/.local/share"); + p->setEnvironment("XDG_DATA_DIRS", m_xdgDataDirs.join(":")); + p->setEnvironment("XDG_CONFIG_HOME", m_homeDir+"/.config"); + p->setEnvironment("XDG_CONFIG_DIRS", m_xdgConfigDirs.join(":")); + p->setEnvironment("DCOPAUTHORITY", m_homeDir+"/.trinity/DCOPserver"); + p->setEnvironment("TDE_KIOSK_NO_PROFILES", "true"); + if (m_noRestrictions) + p->setEnvironment("TDE_KIOSK_NO_RESTRICTIONS", "true"); +} + +bool +KioskRun::prepare() +{ + bool result = setupRuntimeEnv(); + + deleteDir(m_configDir); + deleteDir(locateLocal("data")); + deleteDir(m_desktopPath); + deleteDir(m_homeDir+"/.config"); + deleteDir(m_homeDir+"/.local/share"); + return result; +} + +void +KioskRun::updateSycoca() +{ + // Force update + TQString sycocaUpdateFile = KioskRun::self()->locateLocal("services", "update_tdesycoca"); + TQFile file(sycocaUpdateFile); + file.remove(); + file.open(IO_WriteOnly); + file.close(); + + dcopRef("kded", "tdebuildsycoca").call("recreate"); +} + +TDEProcess* +KioskRun::run(const TQString &cmd, const TQStringList &args) +{ + TDEProcess *proc = new TDEProcess(this); + + applyEnvironment(proc); + + *proc << cmd; + *proc << args; + + proc->start(TDEProcess::NotifyOnExit); + return proc; +} + +class SetEnv +{ +public: + SetEnv(const char *key, const TQString &value) : m_key(key) + { + m_oldValue = getenv(m_key); + setenv(m_key, TQFile::encodeName(value), 1); + } + + ~SetEnv() + { + if (m_oldValue.isEmpty()) + setenv(m_key,"",1); + else + setenv(m_key,m_oldValue.data(),1); + } + +private: + const char* m_key; + TQCString m_oldValue; +}; + +void +KioskRun::setupConfigEnv() +{ + if (m_instance) return; + + // ::locateLocal must be called before we change the env. vars! + TQString newTmpDir = ::locateLocal("tmp", "kioskdir"); + TQString newSocketDir = ::locateLocal("socket", "kioskdir"); + + SetEnv home("HOME", m_homeDir); + TQString kdeHome = m_homeDir+"/.trinity"; + SetEnv tdehome("TDEHOME", kdeHome); + SetEnv tderoothome("TDEROOTHOME", kdeHome); + SetEnv tdedirs("TDEDIRS", m_kdeDirs.join(":")); + SetEnv xdgDataHome("XDG_DATA_HOME", m_homeDir+"/.local/share"); + SetEnv xdgDataDirs("XDG_DATA_DIRS", m_xdgDataDirs.join(":")); + SetEnv xdgConfigHome("XDG_CONFIG_HOME", m_homeDir+"/.config"); + SetEnv xdgConfigDirs("XDG_CONFIG_DIRS", m_xdgConfigDirs.join(":")); + + ::mkdir(TQFile::encodeName(m_homeDir), 0700); + ::mkdir(TQFile::encodeName(kdeHome), 0700); + + // Create temp & socket dirs. + char hostname[256]; + hostname[0] = 0; + gethostname(hostname, 255); + + TQString tmpDir = TQString("%1/%2-%3").arg(kdeHome).arg("tmp").arg(hostname); + deleteDir(tmpDir); + ::mkdir(TQFile::encodeName(newTmpDir), 0700); + ::symlink(TQFile::encodeName(newTmpDir), TQFile::encodeName(tmpDir)); + + TQString socketDir = TQString("%1/%2-%3").arg(kdeHome).arg("socket").arg(hostname); + deleteDir(socketDir); + ::mkdir(TQFile::encodeName(newSocketDir), 0700); + ::symlink(TQFile::encodeName(newSocketDir), TQFile::encodeName(socketDir)); + + m_configDir = TQString("%1/.trinity/share/config/").arg(m_homeDir); + + m_instance = new TDEInstance("kioskrun"); + (void) m_instance->dirs(); // Create TDEStandardDirs obj + + m_desktopPath = m_homeDir + "/Desktop/"; + m_desktopPath = m_instance->config()->readPathEntry( "Desktop", m_desktopPath); + m_desktopPath = TQDir::cleanDirPath( m_desktopPath ); + if ( !m_desktopPath.endsWith("/") ) + m_desktopPath.append('/'); + + { + SetEnv tdehome("TDEHOME", "-"); + SetEnv tderoothome("TDEROOTHOME", "-"); + SetEnv xdgDataHome("XDG_DATA_HOME", m_xdgDataDirs.first()); + SetEnv xdgConfigHome("XDG_CONFIG_HOME", m_xdgConfigDirs.first()); + + m_saveInstance = new TDEInstance("kioskrun"); + (void) m_saveInstance->dirs(); // Create TDEStandardDirs obj + } +} + +TQString +KioskRun::locate(const char *resource, const TQString &filename) +{ + setupConfigEnv(); + + return m_saveInstance->dirs()->findResource(resource, filename); +} + +TQString +KioskRun::locateSave(const char *resource, const TQString &filename) +{ + setupConfigEnv(); + + // split path from filename + int slash = filename.findRev('/')+1; + TQString dir = filename.left(slash); + TQString file = filename.mid(slash); + return m_saveInstance->dirs()->saveLocation(resource, dir, false) + file; +} + +TQString +KioskRun::locateLocal(const char *resource, const TQString &filename) +{ + setupConfigEnv(); + + // split path from filename + int slash = filename.findRev('/')+1; + TQString dir = filename.left(slash); + TQString file = filename.mid(slash); + return m_instance->dirs()->saveLocation(resource, dir, true) + file; +} + + +void +KioskRun::shutdownConfigEnv() +{ + if (!m_instance) return; + + delete m_instance; + m_instance = 0; +} + +class ImmutableStatus +{ +public: + bool m_fileScope; + TQDict<int> m_lines; + TQString m_tmpFile; + bool m_dirty; +}; + + +bool +KioskRun::isConfigImmutable(const TQString &filename, const TQString &group) +{ + (void) configFile(filename); + ImmutableStatus *status = m_immutableStatusCache.find(filename); + assert(status); + if (group.isEmpty()) + return status->m_fileScope; + + return status->m_lines.find(group); +} + +void +KioskRun::setConfigImmutable(const TQString &filename, const TQString &_group, bool bImmutable) +{ + (void) configFile(filename); + ImmutableStatus *status = m_immutableStatusCache.find(filename); + assert(status); + if (_group.isEmpty()) + { + if (status->m_fileScope != bImmutable) + { + status->m_fileScope = bImmutable; + status->m_dirty = true; + m_forceSycocaUpdate = true; + } + } + else + { + TQString group = TQString("[%1]").arg(_group); + if (status->m_lines.find(group)) + { + if (!bImmutable) + { + status->m_lines.remove(group); + status->m_dirty = true; + m_forceSycocaUpdate = true; + } + } + else + { + if (bImmutable) + { + status->m_lines.insert(group, (int *) 1); + status->m_dirty = true; + m_forceSycocaUpdate = true; + } + } + } +} + +static void stripImmutable(TQString &ext) +{ + ext.replace("i", ""); + if (ext == "[$]") + ext = TQString(); +} + +static void addImmutable(TQString &ext) +{ + ext.replace("[$", "[$i"); +} + +TQString +KioskRun::saveImmutableStatus(const TQString &filename) +{ + ImmutableStatus *status = new ImmutableStatus; + status->m_fileScope = false; + status->m_dirty = false; + m_immutableStatusCache.insert(filename, status); + + KTempFile tmp; + tmp.close(); + + TQString newPath = tmp.name(); + status->m_tmpFile = tmp.name(); + + TQString path = m_saveInstance->dirs()->findResource("config", filename); + if (path.isEmpty()) + return newPath; // Nothing to do + + TQFile oldCfg(path); + + if (!oldCfg.open( IO_ReadOnly )) + return newPath; // Error + + TQFile newCfg(newPath); + if (!newCfg.open( IO_WriteOnly )) + return newPath; // Error + + TQTextStream txtIn(&oldCfg); + txtIn.setEncoding(TQTextStream::UnicodeUTF8); + + TQTextStream pTxtOut(&newCfg); + pTxtOut.setEncoding(TQTextStream::UnicodeUTF8); + + TQRegExp immutable("(\\[\\$e?ie?\\])$"); + + // TODO: Use "group+key" instead of "key" as index, otherwise it might not be unique + + while(! txtIn.atEnd()) + { + TQString line = txtIn.readLine().stripWhiteSpace(); + + if (line.startsWith("#")) + { + // Comment, do nothing... + } + else if (line.startsWith("[")) + { + int pos = immutable.searchRev(line); + if (pos != -1) + { + TQString group = line.left(pos); + TQString ext = immutable.cap(0); + stripImmutable(ext); + if (pos == 0) + { + status->m_fileScope = true; + continue; + } + status->m_lines.replace(group, (int *)1 ); + line = group + ext; + } + } + else + { + int equal = line.find('='); + if (equal != -1) + { + TQString key = line.left(equal).stripWhiteSpace(); + int pos = immutable.searchRev(key); + if (pos != -1) + { + key = key.left(pos); + TQString ext = immutable.cap(0); + stripImmutable(ext); + status->m_lines.replace(key, (int *)1 ); + line = key + ext + line.mid(equal); + } + } + } + + pTxtOut << line << endl; + } + oldCfg.close(); + newCfg.close(); + + if (newCfg.status() != IO_Ok ) + { + kdWarning() << "Error writing " << newPath << endl; + return newPath; + } + return newPath; +} + +bool +KioskRun::restoreImmutableStatus(const TQString &filename, bool force) +{ + ImmutableStatus *status = m_immutableStatusCache.take(filename); + if (!status) + { + kdDebug() << "KioskRun::restoreImmutableStatus(" << filename << ") status info missing" << endl; + return true; + } + if (!force && !status->m_dirty) + { + kdDebug() << "KioskRun::restoreImmutableStatus(" << filename << ") not changed" << endl; + delete status; + return true; + } + kdDebug() << "KioskRun::restoreImmutableStatus(" << filename << ") restoring" << endl; + + TQString path = status->m_tmpFile; + + KSaveFile newCfg(path); + if (newCfg.status() != 0) + { + delete status; + return true; // Continue + } + + TQTextStream *pTxtOut = newCfg.textStream(); + pTxtOut->setEncoding(TQTextStream::UnicodeUTF8); + + TQRegExp option("(\\[\\$e\\])$"); + + if (status->m_fileScope) + { + kdDebug() << "Marking file " << filename << " immutable" << endl; + (*pTxtOut) << "[$i]" << endl; + } + + TQFile oldCfg(path); + if (oldCfg.open( IO_ReadOnly )) + { + + TQTextStream txtIn(&oldCfg); + txtIn.setEncoding(TQTextStream::UnicodeUTF8); + + while(! txtIn.atEnd()) + { + TQString line = txtIn.readLine().stripWhiteSpace(); + + if (line.startsWith("#")) + { + // Comment, do nothing... + } + else if (line.startsWith("[")) + { + if (status->m_lines.take(line)) + line += "[$i]"; + } + else + { + int equal = line.find('='); + if (equal != -1) + { + TQString key = line.left(equal).stripWhiteSpace(); + int pos = option.searchRev(key); + if (pos != -1) + { + key = key.left(pos); + TQString ext = option.cap(0); + if (status->m_lines.take(key)) + addImmutable(ext); + line = key + ext + line.mid(equal); + } + else + { + if (status->m_lines.take(key)) + line = key + "[$i]" + line.mid(equal); + } + } + } + + (*pTxtOut) << line << endl; + } + oldCfg.close(); + } + + // Create remaining groups that were marked as immutable + TQDictIterator<int> it( status->m_lines ); + for( ; it.current(); ++it ) + { + TQString group = it.currentKey(); + if ( it.current() ) + (*pTxtOut) << endl << group << "[$i]" << endl; + } + + if (!newCfg.close()) + { + kdWarning() << "Error writing" << path << endl; + delete status; + return true; // Continue + } + + TQString installLocation = m_saveInstance->dirs()->saveLocation("config", TQString(), false) + filename; + if (!install(path, installLocation)) + { + m_immutableStatusCache.insert(filename, status); // Keep it around + return false; + } + delete status; + return true; +} + +bool +KioskRun::flushConfigCache() +{ + while ( !m_saveConfigCache.isEmpty() ) + { + TQDictIterator<TDEConfig> it( m_saveConfigCache ); + TQString file = it.currentKey(); + TDEConfig *config = it.current(); + bool dirty = config->isDirty(); + config->sync(); // Save + if (!restoreImmutableStatus(file, dirty)) + return false; + m_saveConfigCache.remove(file); + } + + if (m_forceSycocaUpdate) + forceSycocaUpdate(); + return true; +} + +TDEConfig * +KioskRun::configFile(const TQString &filename) +{ + TDEConfig *config = m_saveConfigCache.find(filename); + if (config) + return config; + + kdDebug() << "KioskRun::configFile(" << filename << ") loading file" << endl; + + setupConfigEnv(); + + TQString saveLocation = saveImmutableStatus(filename); + config = new KSimpleConfig(saveLocation); + m_saveConfigCache.insert(filename, config); + + return config; +} + +void +KioskRun::makeMutable(bool bMutable) +{ + TDEConfig *config = configFile("kdeglobals"); + + m_noRestrictions = bMutable; + if (KDE::version() < TDE_MAKE_VERSION(3,2,4)) + { + config->setGroup("KDE Action Restrictions"); + if (bMutable) + { + KUser thisUser; + config->writeEntry("kiosk_exception", thisUser.loginName()+":"); // This user, all hosts + } + else + { + config->writeEntry("kiosk_exception", TQString()); + } + } + // Propagate to tdeinit + dcopRef("tdelauncher", "tdelauncher").call("setLaunchEnv", + TQCString("TDE_KIOSK_NO_RESTRICTIONS"), TQCString(m_noRestrictions ? "true" : "")); + + setConfigImmutable("kdeglobals", "KDE Action Restrictions", true); +} + +TQStringList +KioskRun::newConfigFiles() +{ + setupConfigEnv(); + + TQStringList exceptions; + exceptions << "tdeconf_updaterc"; + + TQStringList result; + TQDir dir(m_configDir); + dir.setFilter( TQDir::Files | TQDir::NoSymLinks ); + + const TQFileInfoList *list = dir.entryInfoList(); + if (!list) return result; + + TQFileInfoListIterator it( *list ); + TQFileInfo *fi; + while ( (fi = it.current()) != 0 ) + { + TQString file = fi->fileName(); + if (!file.endsWith("~") && !exceptions.contains(file)) // Skip backup files & exceptions + result.append(file); + ++it; + } + return result; +} + +void +KioskRun::mergeConfigFile(const TQString &filename) +{ + TDEConfig *saveCfg = configFile(filename); + + kdDebug() << "KioskRun::mergeConfigFile(" << (m_configDir + filename) << ")" << endl; + KSimpleConfig newCfg(m_configDir + filename); + + TQStringList groups = newCfg.groupList(); + for(TQStringList::ConstIterator it = groups.begin(); + it != groups.end(); ++it) + { + saveCfg->setGroup(*it); + TQMap<TQString, TQString> map = newCfg.entryMap(*it); + for(TQMap<TQString, TQString>::Iterator it2 = map.begin(); + it2 != map.end(); ++it2) + { +#ifdef DEBUG_ENTRIES +tqWarning("[%s] %s --> %s", (*it).latin1(), it2.key().latin1(), it2.data().latin1()); +#endif + saveCfg->writeEntry(it2.key(), it2.data()); + } + } +} + +bool +KioskRun::setupRuntimeEnv() +{ + if (m_dcopClient) return true; + + KioskRunProgressDialog dlg(kapp->mainWidget(), "kioskrun_progress", + i18n("Setting Up Configuration Environment"), + i18n("Setting up configuration environment.")); + + char hostname[256]; + hostname[0] = 0; + gethostname(hostname, 255); + TQString cacheDir = TQString("%1/.trinity/cache-%2").arg(m_homeDir).arg(hostname); + + deleteDir(cacheDir); + TDEStandardDirs::makeDir(cacheDir); + deleteDir(m_homeDir+"/.qt"); + ::unlink(TQFile::encodeName(m_homeDir+".kderc")); + + + TQString iceAuth = TQString("%1/.ICEauthority").arg(TQDir::homeDirPath()); + setenv("ICEAUTHORITY", TQFile::encodeName(iceAuth), 0); // Don't overwrite existing setting + + TQString xAuth = TQString("%1/.Xauthority").arg(TQDir::homeDirPath()); + setenv("XAUTHORITY", TQFile::encodeName(xAuth), 0); // Don't overwrite existing setting + + TQString dcopServerFile = m_homeDir+"/.trinity/DCOPserver"; + + TDEProcess tdeinit; + + applyEnvironment(&tdeinit); + + tdeinit << "tdeinit"; + + connect(&tdeinit, TQT_SIGNAL(processExited(TDEProcess *)), &dlg, TQT_SLOT(slotFinished())); + + tdeinit.start(TDEProcess::NotifyOnExit); + + dlg.exec(); + + TQCString dcopSrv; + TQFile f(dcopServerFile); + if (f.open(IO_ReadOnly)) + { + int size = TQMIN( 1024, f.size() ); // protection against a huge file + TQCString contents( size+1 ); + if ( f.readBlock( contents.data(), size ) == size ) + { + contents[size] = '\0'; + int pos = contents.find('\n'); + if ( pos == -1 ) // Shouldn't happen + dcopSrv = contents; + else + dcopSrv = contents.left( pos ); + } + } + + if (dcopSrv.isEmpty()) + { + kdWarning() << "Error reading " << dcopServerFile << endl; + m_dcopClient = new DCOPClient; + shutdownRuntimeEnv(); + return false; + } + + m_dcopClient = new DCOPClient; + m_dcopClient->setServerAddress(dcopSrv); + unsetenv("DCOPSERVER"); // Don't propagate it + m_dcopClient->attach(); + return true; +} + +void +KioskRun::shutdownRuntimeEnv() +{ + if (!m_dcopClient) return; + + delete m_dcopClient; + m_dcopClient = 0; + + TDEProcess tdeinit; + applyEnvironment(&tdeinit); + + tdeinit << "tdeinit_shutdown"; + + tdeinit.start(TDEProcess::Block); + + TDEProcess dcopserver; + applyEnvironment(&dcopserver); + + dcopserver << "dcopserver_shutdown"; + + dcopserver.start(TDEProcess::Block); +} + +DCOPRef +KioskRun::dcopRef(const TQCString &appId, const TQCString &objId) +{ + if (!setupRuntimeEnv()) + return DCOPRef(); + DCOPRef ref(appId, objId); + ref.setDCOPClient(m_dcopClient); + return ref; +} + +// Lookup the setting for a custom action +bool +KioskRun::lookupCustomAction(const TQString &action) +{ + TDEConfig *cfg = KioskRun::self()->configFile("kdeglobals"); + cfg->setGroup("KDE Custom Restrictions"); + return cfg->readBoolEntry(action, false); +} + +// Change the setting for a custom action +void +KioskRun::setCustomAction(const TQString &action, bool checked) +{ + TDEConfig *cfg = KioskRun::self()->configFile("kdeglobals"); + cfg->setGroup("KDE Custom Restrictions"); + if (cfg->readBoolEntry(action, false) != checked) + { + cfg->writeEntry(action, checked); + KioskRun::self()->scheduleSycocaUpdate(); + + if (action == "restrict_file_browsing") + { + setCustomRestrictionFileBrowsing(checked); + } + } +} + +// Create directory +bool +KioskRun::createDir(const TQString &dir) +{ + if (TQDir(dir).exists()) + return true; // Exists already + + KURL dest; + if (!m_isRoot || (m_user != "root")) + { + dest.setProtocol("fish"); + dest.setHost("localhost"); + dest.setUser(m_user); + } + dest.setPath(dir); + + if (dir.length() > 1) + { + KURL parent = dest.upURL(); + + bool result = createDir(parent.path()); + if (!result) + return false; + } + + do + { + if (NETACCESS::exists(dest, false, kapp->mainWidget())) + return true; + + bool result = NETACCESS::mkdir(dest, kapp->mainWidget(), 0755); + if (result == true) + return true; + + TQString error = NETACCESS::lastErrorString(); + TQString msg; + + if (error.isEmpty()) + msg = i18n("<qt>The directory <b>%1</b> could not be created because of an unspecified problem.<p>") + .arg(dir); + else + msg = i18n("<qt>The directory <b>%1</b> could not be created because of the following problem:" + "<p>%2<p>") + .arg(dir, NETACCESS::lastErrorString()); + + msg += i18n("Without this directory your changes can not be saved.<p>" + "Do you want to retry creating the directory or abort the saving of changes?</qt>"); + + int msgResult = KMessageBox::warningYesNo(kapp->mainWidget(), msg, TQString(), + i18n("&Retry"), i18n("&Abort")); + + if (msgResult == KMessageBox::No) + return false; + + // Maybe the user created it in the meantime + if (TQDir(dir).exists()) + return true; // Exists already + } + while (true); + return false; +} + +// Create directory +bool +KioskRun::createRemoteDirRecursive(const KURL &dest, bool ask) +{ + if (NETACCESS::exists(dest, false, kapp->mainWidget())) + return true; + + KURL parent = dest.upURL(); + + if (NETACCESS::exists(dest, false, kapp->mainWidget())) + { + return createRemoteDir(dest); + } + + if (ask) + { + // Parent doesn't exist, + int result = KMessageBox::warningContinueCancel(kapp->mainWidget(), + i18n("<qt>The directory <b>%1</b> does not yet exist. " + "Do you want to create it?").arg(parent.prettyURL()), TQString(), + i18n("Create &Dir")); + if (result != KMessageBox::Continue) + return false; + } + + TQString path = dest.path(1); + int i = 0; + while ( (i = path.find('/', i+1)) != -1) + { + parent.setPath(path.left(i+1)); + if (! createRemoteDir(parent)) + return false; + } + return true; +} + +// Create directory +bool +KioskRun::createRemoteDir(const KURL &dest) +{ + do + { + if (NETACCESS::exists(dest, false, kapp->mainWidget())) + return true; + + if (NETACCESS::mkdir(dest, kapp->mainWidget(), 0755)) + return true; + +#if KDE_IS_VERSION(3,2,91) + if (NETACCESS::lastError() == TDEIO::ERR_DIR_ALREADY_EXIST) + return true; +#endif + + //TODO Check directory already exists error + TQString error = NETACCESS::lastErrorString(); + TQString msg; + + if (error.isEmpty()) + msg = i18n("<qt>The directory <b>%1</b> could not be created because of an unspecified problem.<p>") + .arg(dest.prettyURL()); + else + msg = i18n("<qt>The directory <b>%1</b> could not be created because of the following problem:" + "<p>%2<p>") + .arg(dest.prettyURL(), NETACCESS::lastErrorString()); + + msg += i18n("Without this directory your files can not be uploaded.<p>" + "Do you want to retry creating the directory or abort uploading?</qt>"); + + int msgResult = KMessageBox::warningYesNo(kapp->mainWidget(), msg, TQString(), + i18n("&Retry"), i18n("&Abort")); + + if (msgResult == KMessageBox::No) + return false; + } + while (true); + return false; +} + +// Install file +bool +KioskRun::install(const TQString &file, const TQString &destination) +{ + KURL dest; + if (!m_isRoot || (m_user != "root")) + { + dest.setProtocol("fish"); + dest.setHost("localhost"); + dest.setUser(m_user); + } + dest.setPath(destination); + + if (!createDir(dest.upURL().path())) + return false; + + do + { + KURL src; + src.setPath(file); + bool result = NETACCESS::file_copy(src, dest, 0644, true, false, kapp->mainWidget()); + if (result == true) + { + ::unlink(TQFile::encodeName(file)); + return true; + } + + TQString error = NETACCESS::lastErrorString(); + TQString msg; + if (error.isEmpty()) + msg = i18n("<qt>The file <b>%1</b> could not be installed because of an unspecified problem.") + .arg(destination); + else + msg = i18n("<qt>The file <b>%1</b> could not be installed because of the following problem:" + "<p>%2<p>") + .arg(destination, NETACCESS::lastErrorString()); + + msg += i18n("Do you want to retry the installation or abort the saving of changes?</qt>"); + + int msgResult = KMessageBox::warningYesNo(kapp->mainWidget(), msg, TQString(), + i18n("&Retry"), i18n("&Abort")); + + if (msgResult == KMessageBox::No) + return false; + } + while (true); + return false; +} + +// Upload file +bool +KioskRun::uploadRemote(const TQString &file, const KURL &dest) +{ + do + { + KURL src; + src.setPath(file); + bool result = NETACCESS::file_copy(src, dest, 0644, true, false, kapp->mainWidget()); + if (result == true) + return true; + + TQString error = NETACCESS::lastErrorString(); + TQString msg; + if (error.isEmpty()) + msg = i18n("<qt>The file <b>%1</b> could not be uploaded to <b>%2</b> because of an unspecified problem.") + .arg(file, dest.prettyURL()); + else + msg = i18n("<qt>The file <b>%1</b> could not be uploaded to <b>%2</b> because of the following problem:" + "<p>%3<p>") + .arg(file, dest.prettyURL(),NETACCESS::lastErrorString()); + + msg += i18n("Do you want to retry or abort the uploading?</qt>"); + + int msgResult = KMessageBox::warningYesNo(kapp->mainWidget(), msg, TQString(), + i18n("&Retry"), i18n("&Abort")); + + if (msgResult == KMessageBox::No) + return false; + } + while (true); + return false; +} + +// Remove file +bool +KioskRun::remove(const TQString &destination) +{ + KURL dest; + if (!m_isRoot || (m_user != "root")) + { + dest.setProtocol("fish"); + dest.setHost("localhost"); + dest.setUser(m_user); + } + dest.setPath(destination); + + return NETACCESS::del(dest, kapp->mainWidget()); +} + +// Move file or directory +bool +KioskRun::move(const TQString &source, const TQString &destination, const TQStringList &files) +{ + KURL src; + KURL dest; + if (!m_isRoot || (m_user != "root")) + { + dest.setProtocol("fish"); + dest.setHost("localhost"); + dest.setUser(m_user); + src.setProtocol("fish"); + src.setHost("localhost"); + src.setUser(m_user); + } + + for(TQStringList::ConstIterator it = files.begin(); + it != files.end(); ++it) + { + src.setPath(source + *it); + dest.setPath(destination + *it); + +kdDebug() << "Moving " << src << " --> " << dest << endl; + if (!createRemoteDirRecursive(dest.upURL(), false)) + return false; + + if (!NETACCESS::file_move(src, dest, -1, true, false, kapp->mainWidget())) + { + // TODO add error message + retry + return false; + } + } + return true; +} + +// Read information of profile @p profile +void +KioskRun::getProfileInfo(const TQString &profile, TQString &description, TQString &installDir, TQString &installUser) +{ + TDEConfig *config = kapp->config(); + + TQString defaultInstallDir = getProfilePrefix(); + if (defaultInstallDir.isEmpty()) + { + defaultInstallDir = "/etc/kde-profile/"; + } + if (!defaultInstallDir.endsWith("/")) + defaultInstallDir.append("/"); + TQString tmp = profile; + tmp.replace(" ", "_"); + tmp.replace(":", "_"); + tmp.replace("/", "_"); + defaultInstallDir += tmp+"/"; + + TQString group = TQString("Directories-%1").arg(profile); + config->setGroup(group); + + installDir = config->readEntry("prefixes", defaultInstallDir); + if (!installDir.endsWith("/")) + installDir.append("/"); + + TQString profileInfoFile = installDir + ".kdeprofile"; + if (TQFile::exists(profileInfoFile)) + { + KSimpleConfig profileInfo(profileInfoFile, true); + description = profileInfo.readEntry("Description"); + installUser = profileInfo.readEntry("InstallUser", "root"); + return; + } + + TQString defaultDescription; + if (profile == "default") + defaultDescription = i18n("Default profile"); + + description = config->readEntry("ProfileDescription", defaultDescription); + installUser = config->readEntry("ProfileInstallUser", "root"); +} + +KSimpleConfig * +KioskRun::openKderc() +{ + if (m_localKdercConfig) + return m_localKdercConfig; + + KURL settingsUrl; + settingsUrl.setPath(m_kderc); + + m_localKderc = ::locateLocal("tmp", "kderc_"+kapp->randomString(5)); + ::unlink(TQFile::encodeName(m_localKderc)); + + KURL localCopyUrl; + localCopyUrl.setPath(m_localKderc); + + if (TQFile::exists(settingsUrl.path())) + { + + while (!NETACCESS::copy(settingsUrl, localCopyUrl, kapp->mainWidget())) + { + TQString error = NETACCESS::lastErrorString(); + TQString msg; + if (error.isEmpty()) + msg = i18n("<qt>The file <b>%1</b> could not be accessed because of an unspecified problem.") + .arg(settingsUrl.path()); + else + msg = i18n("<qt>The file <b>%1</b> could not be accessed because of the following problem:" + "<p>%2<p>") + .arg(settingsUrl.path(), error); + + msg += i18n("Do you want to retry the operation or abort the saving of changes?</qt>"); + + int msgResult = KMessageBox::warningYesNo(kapp->mainWidget(), msg, TQString(), + i18n("&Retry"), i18n("&Abort")); + + if (msgResult == KMessageBox::No) + return 0; + } + } + + m_localKdercConfig = new KSimpleConfig(m_localKderc); + return m_localKdercConfig; +} + +bool +KioskRun::closeKderc() +{ + if (!m_localKdercConfig) + return false; + m_localKdercConfig->sync(); + delete m_localKdercConfig; + m_localKdercConfig = 0; + + TQString saveUser = m_user; + m_user = "root"; + bool result = install(m_localKderc, m_kderc); + m_localKderc = TQString(); + m_user = saveUser; + kapp->config()->reparseConfiguration(); + return result; +} + +// Store information for profile @p profile +bool +KioskRun::setProfileInfo(const TQString &profile, const TQString &description, const TQString &_installDir, const TQString &installUser, bool deleteProfile, bool deleteFiles) +{ + TQString installDir = _installDir; + if (!installDir.endsWith("/")) + installDir.append("/"); + + TQString saveProfileInfo = installDir + ".kdeprofile"; + KSimpleConfig profileInfo(saveProfileInfo, true); + TQString oldDescription = profileInfo.readEntry("Description"); + TQString oldInstallUser = profileInfo.readEntry("InstallUser"); + if (deleteProfile && !installDir.isEmpty()) + { + bool result = true; + KioskSync profileDir(kapp->mainWidget()); + profileDir.addDir(installDir, KURL()); + TQStringList allFiles = profileDir.listFiles(); + allFiles.remove(".kdeprofile"); + if (allFiles.isEmpty()) + { + if (TQDir(installDir).exists()) + { + m_user = installUser; + remove(installDir); + m_user = TQString(); + } + } + else if (deleteFiles) + { + int msgResult = KMessageBox::warningYesNoCancelList(kapp->mainWidget(), + i18n("<qt>The profile directory <b>%1</b> contains the following files, " + "do you wish to delete these files?").arg(installDir), + allFiles, + i18n("Deleting Profile"), +#if KDE_IS_VERSION(3,2,91) + KStdGuiItem::del(), +#else + i18n("&Delete"), +#endif + i18n("&Keep Files") + ); + switch(msgResult) + { + case KMessageBox::Yes: + // Delete files + m_user = installUser; + result = remove(installDir); + m_user = TQString(); + if (!result) + return false; + break; + + case KMessageBox::No: + // Keep files + break; + + default: + // Cancel + return false; + } + } + + m_user = installUser; + if (TQFile::exists(saveProfileInfo)) + result = remove(saveProfileInfo); + m_user = TQString(); + if (!result) + return false; + } + else if ((description != oldDescription) || + (installUser != oldInstallUser)) + { + TQString localProfileInfo = ::locateLocal("tmp", "kdeprofile_"+kapp->randomString(5)); + ::unlink(TQFile::encodeName(localProfileInfo)); + KSimpleConfig newProfileInfo(localProfileInfo); + newProfileInfo.writeEntry("Description", description); + newProfileInfo.writeEntry("InstallUser", installUser); + newProfileInfo.sync(); + bool result = install(localProfileInfo, saveProfileInfo); + if (!result) + return false; + } + + KUser thisUser; + TQString newAdmin = thisUser.loginName()+":"; // This user, all hosts + + TDEConfig *config = kapp->config(); + + config->setGroup("Directories"); + TQString oldAdmin = config->readEntry("kioskAdmin"); + + TQString group = TQString("Directories-%1").arg(profile); + config->setGroup(group); + + if ((installDir == config->readEntry("prefixes")) && + (newAdmin == oldAdmin) && + !deleteProfile) + return true; // Nothing to do + + KSimpleConfig *cfg = openKderc(); + if (!cfg) + return false; + + cfg->setGroup("Directories"); + cfg->writeEntry("kioskAdmin", newAdmin); + + if (deleteProfile) + { + cfg->deleteGroup(group); + } + else + { + cfg->setGroup(group); + // TODO: update prefixes + cfg->writeEntry("prefixes", installDir); + } + cfg->sync(); + + return closeKderc(); +} + +bool +KioskRun::deleteProfile(const TQString &profile, bool deleteFiles) +{ + TQString description; + TQString installDir; + TQString installUser; + getProfileInfo(profile, description, installDir, installUser); + return setProfileInfo(profile, description, installDir, installUser, true, deleteFiles); +} + +// Read profile prefix +TQString +KioskRun::getProfilePrefix() +{ + TDEConfig *config = kapp->config(); + + config->setGroup("Directories"); + + TQString prefix = config->readEntry("profileDirsPrefix"); + if (!prefix.isEmpty() && !prefix.endsWith("/")) + prefix.append('/'); + return prefix; +} + +// Store profile prefix +bool +KioskRun::setProfilePrefix(const TQString &_prefix) +{ + TQString prefix = _prefix; + + if (!prefix.isEmpty() && !prefix.endsWith("/")) + prefix.append('/'); + + if (prefix == getProfilePrefix()) + return true; // Nothing to do + + KSimpleConfig *cfg = openKderc(); + if (!cfg) + return false; + + cfg->setGroup("Directories"); + cfg->writeEntry("profileDirsPrefix", prefix); + + cfg->sync(); + + return closeKderc(); +} + +TQString +KioskRun::newProfile() +{ + TQString profilePrefix = getProfilePrefix(); + + TDEConfig *config = kapp->config(); + for(int p = 1; p; p++) + { + TQString profile = TQString("profile%1").arg(p); + TQString group = TQString("Directories-%1").arg(profile); + if (!config->hasGroup(group)) + { + if (profilePrefix.isEmpty()) + return profile; + + TQString profileDir = profilePrefix + profile; + if (!TQDir(profileDir).exists() && !TQFile::exists(profileDir)) + return profile; + + // Keep on looking... + } + } + return TQString(); +} + +TQStringList +KioskRun::allProfiles() +{ + TDEConfig *config = kapp->config(); + TQStringList groups = config->groupList(); + TQStringList profiles; + TQStringList directories; + for(TQStringList::ConstIterator it = groups.begin(); + it != groups.end(); ++it) + { + if (!(*it).startsWith("Directories-")) + continue; + profiles.append((*it).mid(12)); + config->setGroup(*it); + TQString installDir = config->readEntry("prefixes"); + if (!installDir.endsWith("/")) + installDir.append("/"); + directories.append(installDir); + } + + TQString profilePrefix = getProfilePrefix(); + if (!profilePrefix.isEmpty()) + { + TQDir dir(profilePrefix, TQString(), TQDir::Unsorted, TQDir::Dirs); + TQStringList profileDirs = dir.entryList(); + for(TQStringList::ConstIterator it = profileDirs.begin(); + it != profileDirs.end(); ++it) + { + if ((*it).startsWith(".")) + continue; + TQString dir = profilePrefix + *it + "/"; + if (directories.contains(dir)) + { + kdDebug() << "Skipping " << dir << ", dir already listed" << endl; + continue; + } + if (profiles.contains(*it)) + { + kdDebug() << "Skipping " << dir << ", profile [" << (*it) << "] already listed" << endl; + continue; + } + + if (!TQFile::exists(dir+".kdeprofile")) + { + kdDebug() << "Skipping " << dir << ", no profile info" << endl; + continue; + } + profiles.append(*it); + directories.append(dir); + } + } + + if (!profiles.contains("default")) + profiles.append("default"); + + return profiles; +} + +void +KioskRun::getUserProfileMappings( ProfileMapping &groups, ProfileMapping &users, TQStringList &groupOrder) +{ + groups.clear(); + users.clear(); + + TDEConfig *config = kapp->config(); + config->setGroup("Directories"); + TQString mapFile = config->readEntry("userProfileMapFile"); + + if (mapFile.isEmpty() || !TQFile::exists(mapFile)) + return; + + KSimpleConfig mapCfg(mapFile, true); + + mapCfg.setGroup("General"); + groupOrder = mapCfg.readListEntry("groups"); + + mapCfg.setGroup("Groups"); + for ( TQStringList::ConstIterator it = groupOrder.begin(); + it != groupOrder.end(); ++it ) + { + TQString group = *it; + TQStringList profiles = mapCfg.readListEntry(group); + if (!profiles.isEmpty()) + groups.insert(group, profiles); + } + + TQMap<TQString, TQString> cfg_users = mapCfg.entryMap("Users"); + for ( TQMap<TQString, TQString>::Iterator it = cfg_users.begin(); + it != cfg_users.end(); ++it ) + { + TQString user = it.key(); + TQStringList profiles = TQStringList::split(",", it.data()); + if (!profiles.isEmpty()) + users.insert(user, profiles); + } +} + +bool +KioskRun::setUserProfileMappings( const ProfileMapping &groups, const ProfileMapping &users, const TQStringList &groupOrder) +{ + TDEConfig *config = kapp->config(); + config->setGroup("Directories"); + TQString mapFile = config->readEntry("userProfileMapFile"); + if (mapFile.isEmpty()) + { + mapFile = "/etc/kde-user-profile"; + + KSimpleConfig *cfg = openKderc(); + if (!cfg) + return false; + + cfg->setGroup("Directories"); + cfg->writeEntry("userProfileMapFile", mapFile); + if (!closeKderc()) + return false; + } + + TQString localMapFile = ::locateLocal("tmp", "kde-user-profile_"+kapp->randomString(5)); + ::unlink(TQFile::encodeName(localMapFile)); + + KSimpleConfig mapConfig(localMapFile); + + mapConfig.setGroup("General"); + mapConfig.writeEntry("groups", groupOrder); + + KioskRun::ProfileMapping::ConstIterator it; + + mapConfig.setGroup("Groups"); + for ( it = groups.begin(); it != groups.end(); ++it ) + { + TQString group = it.key(); + mapConfig.writeEntry(group, it.data()); + } + mapConfig.setGroup("Users"); + for ( it = users.begin(); it != users.end(); ++it ) + { + TQString user = it.key(); + mapConfig.writeEntry(user, it.data()); + } + + mapConfig.sync(); + + TQString saveUser = m_user; + m_user = "root"; + bool result = install(localMapFile, mapFile); + m_user = saveUser; + return result; +} + +void +KioskRun::forceSycocaUpdate() +{ + // Touch $TDEDIR/share/services/update_tdesycoca + KTempFile tempFile; + tempFile.close(); + TQString sycocaUpdateFile = locateSave("services", "update_tdesycoca"); + remove(sycocaUpdateFile); + install(tempFile.name(), sycocaUpdateFile); +} + +void +KioskRun::scheduleSycocaUpdate() +{ + m_forceSycocaUpdate = true; +} + +void +KioskRun::setCustomRestrictionFileBrowsing(bool restrict) +{ + TQString file = "kdeglobals"; + TQString group = "KDE URL Restrictions"; + TDEConfig *cfg = KioskRun::self()->configFile(file); + cfg->setGroup(group); + int count = cfg->readNumEntry("rule_count"); + TQStringList urlRestrictions; + for(int i = 0; i < count; i++) + { + TQString key = TQString("rule_%1").arg(i+1); + if (cfg->hasKey(key)) + urlRestrictions.append(cfg->readEntry(key)); + } + + TQStringList newRestrictions; + newRestrictions << "list,,,,file,,,false"; + newRestrictions << "list,,,,file,,$HOME,true"; + + for(TQStringList::ConstIterator it = newRestrictions.begin(); + it != newRestrictions.end(); ++it) + { + urlRestrictions.remove(*it); + } + + if (restrict) + { + newRestrictions += urlRestrictions; + urlRestrictions = newRestrictions; + } + + count = urlRestrictions.count(); + cfg->writeEntry("rule_count", count); + + for(int i = 0; i < count; i++) + { + TQString key = TQString("rule_%1").arg(i+1); + cfg->writeEntry(key, urlRestrictions[i]); + } + KioskRun::self()->setConfigImmutable(file, group, true); +} + +KioskRunProgressDialog::KioskRunProgressDialog(TQWidget *parent, const char *name, + const TQString &caption, const TQString &text) + : KProgressDialog(parent, name, caption, text, true) +{ + connect(&m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotProgress())); + progressBar()->setTotalSteps(20); + m_timeStep = 700; + m_timer.start(m_timeStep); + setAutoClose(false); +} + +void +KioskRunProgressDialog::slotProgress() +{ + int p = progressBar()->progress(); + if (p == 18) + { + progressBar()->reset(); + progressBar()->setProgress(1); + m_timeStep = m_timeStep * 2; + m_timer.start(m_timeStep); + } + else + { + progressBar()->setProgress(p+1); + } +} + +void +KioskRunProgressDialog::slotFinished() +{ + progressBar()->setProgress(20); + m_timer.stop(); + TQTimer::singleShot(1000, this, TQT_SLOT(close())); +} + + +#include "kioskrun.moc" + |