/* * kioskrun.cpp * * Copyright (C) 2004 Waldo Bastian * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kiosksync.h" #include #define NETACCESS KIO::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()+"/.kde-test"; KCmdLineArgs *args = KCmdLineArgs::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(':', KGlobal::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 = KGlobal::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)); KProcess proc; proc << "rm" << "-rf" << dir; proc.start(KProcess::Block); } void KioskRun::applyEnvironment(KProcess *p) { p->setEnvironment("HOME", m_homeDir); p->setEnvironment("KDEHOME", m_homeDir+"/.kde"); p->setEnvironment("KDEROOTHOME", m_homeDir+"/.kde"); p->setEnvironment("KDEDIRS", 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+"/.kde/DCOPserver"); p->setEnvironment("KDE_KIOSK_NO_PROFILES", "true"); if (m_noRestrictions) p->setEnvironment("KDE_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_ksycoca"); TQFile file(sycocaUpdateFile); file.remove(); file.open(IO_WriteOnly); file.close(); dcopRef("kded", "kbuildsycoca").call("recreate"); } KProcess* KioskRun::run(const TQString &cmd, const TQStringList &args) { KProcess *proc = new KProcess(this); applyEnvironment(proc); *proc << cmd; *proc << args; proc->start(KProcess::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+"/.kde"; SetEnv kdehome("KDEHOME", kdeHome); SetEnv kderoothome("KDEROOTHOME", kdeHome); SetEnv kdedirs("KDEDIRS", 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").tqarg(kdeHome).tqarg("tmp").tqarg(hostname); deleteDir(tmpDir); ::mkdir(TQFile::encodeName(newTmpDir), 0700); ::symlink(TQFile::encodeName(newTmpDir), TQFile::encodeName(tmpDir)); TQString socketDir = TQString("%1/%2-%3").tqarg(kdeHome).tqarg("socket").tqarg(hostname); deleteDir(socketDir); ::mkdir(TQFile::encodeName(newSocketDir), 0700); ::symlink(TQFile::encodeName(newSocketDir), TQFile::encodeName(socketDir)); m_configDir = TQString("%1/.kde/share/config/").tqarg(m_homeDir); m_instance = new KInstance("kioskrun"); (void) m_instance->dirs(); // Create KStandardDirs 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 kdehome("KDEHOME", "-"); SetEnv kderoothome("KDEROOTHOME", "-"); SetEnv xdgDataHome("XDG_DATA_HOME", m_xdgDataDirs.first()); SetEnv xdgConfigHome("XDG_CONFIG_HOME", m_xdgConfigDirs.first()); m_saveInstance = new KInstance("kioskrun"); (void) m_saveInstance->dirs(); // Create KStandardDirs 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 ImmutabletqStatus { public: bool m_fileScope; TQDict m_lines; TQString m_tmpFile; bool m_dirty; }; bool KioskRun::isConfigImmutable(const TQString &filename, const TQString &group) { (void) configFile(filename); ImmutabletqStatus *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); ImmutabletqStatus *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]").tqarg(_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::saveImmutabletqStatus(const TQString &filename) { ImmutabletqStatus *status = new ImmutabletqStatus; 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::restoreImmutabletqStatus(const TQString &filename, bool force) { ImmutabletqStatus *status = m_immutableStatusCache.take(filename); if (!status) { kdDebug() << "KioskRun::restoreImmutabletqStatus(" << filename << ") status info missing" << endl; return true; } if (!force && !status->m_dirty) { kdDebug() << "KioskRun::restoreImmutabletqStatus(" << filename << ") not changed" << endl; delete status; return true; } kdDebug() << "KioskRun::restoreImmutabletqStatus(" << 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 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 it( m_saveConfigCache ); TQString file = it.currentKey(); KConfig *config = it.current(); bool dirty = config->isDirty(); config->sync(); // Save if (!restoreImmutabletqStatus(file, dirty)) return false; m_saveConfigCache.remove(file); } if (m_forceSycocaUpdate) forceSycocaUpdate(); return true; } KConfig * KioskRun::configFile(const TQString &filename) { KConfig *config = m_saveConfigCache.find(filename); if (config) return config; kdDebug() << "KioskRun::configFile(" << filename << ") loading file" << endl; setupConfigEnv(); TQString saveLocation = saveImmutabletqStatus(filename); config = new KSimpleConfig(saveLocation); m_saveConfigCache.insert(filename, config); return config; } void KioskRun::makeMutable(bool bMutable) { KConfig *config = configFile("kdeglobals"); m_noRestrictions = bMutable; if (KDE::version() < KDE_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 kdeinit dcopRef("klauncher", "klauncher").call("setLaunchEnv", TQCString("KDE_KIOSK_NO_RESTRICTIONS"), TQCString(m_noRestrictions ? "true" : "")); setConfigImmutable("kdeglobals", "KDE Action Restrictions", true); } TQStringList KioskRun::newConfigFiles() { setupConfigEnv(); TQStringList exceptions; exceptions << "kconf_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) { KConfig *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 map = newCfg.entryMap(*it); for(TQMap::Iterator it2 = map.begin(); it2 != map.end(); ++it2) { #ifdef DEBUG_ENTRIES qWarning("[%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/.kde/cache-%2").tqarg(m_homeDir).tqarg(hostname); deleteDir(cacheDir); KStandardDirs::makeDir(cacheDir); deleteDir(m_homeDir+"/.qt"); ::unlink(TQFile::encodeName(m_homeDir+".kderc")); TQString iceAuth = TQString("%1/.ICEauthority").tqarg(TQDir::homeDirPath()); setenv("ICEAUTHORITY", TQFile::encodeName(iceAuth), 0); // Don't overwrite existing setting TQString xAuth = TQString("%1/.Xauthority").tqarg(TQDir::homeDirPath()); setenv("XAUTHORITY", TQFile::encodeName(xAuth), 0); // Don't overwrite existing setting TQString dcopServerFile = m_homeDir+"/.kde/DCOPserver"; KProcess kdeinit; applyEnvironment(&kdeinit); kdeinit << "kdeinit"; connect(&kdeinit, TQT_SIGNAL(processExited(KProcess *)), &dlg, TQT_SLOT(slotFinished())); kdeinit.start(KProcess::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; KProcess kdeinit; applyEnvironment(&kdeinit); kdeinit << "kdeinit_shutdown"; kdeinit.start(KProcess::Block); KProcess dcopserver; applyEnvironment(&dcopserver); dcopserver << "dcopserver_shutdown"; dcopserver.start(KProcess::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) { KConfig *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) { KConfig *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("The directory %1 could not be created because of an unspecified problem.

") .tqarg(dir); else msg = i18n("The directory %1 could not be created because of the following problem:" "

%2

") .tqarg(dir, NETACCESS::lastErrorString()); msg += i18n("Without this directory your changes can not be saved.

" "Do you want to retry creating the directory or abort the saving of changes?"); 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("The directory %1 does not yet exist. " "Do you want to create it?").tqarg(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() == KIO::ERR_DIR_ALREADY_EXIST) return true; #endif //TODO Check directory already exists error TQString error = NETACCESS::lastErrorString(); TQString msg; if (error.isEmpty()) msg = i18n("The directory %1 could not be created because of an unspecified problem.

") .tqarg(dest.prettyURL()); else msg = i18n("The directory %1 could not be created because of the following problem:" "

%2

") .tqarg(dest.prettyURL(), NETACCESS::lastErrorString()); msg += i18n("Without this directory your files can not be uploaded.

" "Do you want to retry creating the directory or abort uploading?"); 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("The file %1 could not be installed because of an unspecified problem.") .tqarg(destination); else msg = i18n("The file %1 could not be installed because of the following problem:" "

%2

") .tqarg(destination, NETACCESS::lastErrorString()); msg += i18n("Do you want to retry the installation or abort the saving of changes?"); 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("The file %1 could not be uploaded to %2 because of an unspecified problem.") .tqarg(file, dest.prettyURL()); else msg = i18n("The file %1 could not be uploaded to %2 because of the following problem:" "

%3

") .tqarg(file, dest.prettyURL(),NETACCESS::lastErrorString()); msg += i18n("Do you want to retry or abort the uploading?"); 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) { KConfig *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").tqarg(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("The file %1 could not be accessed because of an unspecified problem.") .tqarg(settingsUrl.path()); else msg = i18n("The file %1 could not be accessed because of the following problem:" "

%2

") .tqarg(settingsUrl.path(), error); msg += i18n("Do you want to retry the operation or abort the saving of changes?"); 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("The profile directory %1 contains the following files, " "do you wish to delete these files?").tqarg(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 KConfig *config = kapp->config(); config->setGroup("Directories"); TQString oldAdmin = config->readEntry("kioskAdmin"); TQString group = TQString("Directories-%1").tqarg(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() { KConfig *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(); KConfig *config = kapp->config(); for(int p = 1; p; p++) { TQString profile = TQString("profile%1").tqarg(p); TQString group = TQString("Directories-%1").tqarg(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() { KConfig *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(); KConfig *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 cfg_users = mapCfg.entryMap("Users"); for ( TQMap::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) { KConfig *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 $KDEDIR/share/services/update_ksycoca KTempFile tempFile; tempFile.close(); TQString sycocaUpdateFile = locateSave("services", "update_ksycoca"); 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"; KConfig *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").tqarg(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").tqarg(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"