diff options
Diffstat (limited to 'filesharing/advanced/kcm_sambaconf/sambafile.cpp')
-rw-r--r-- | filesharing/advanced/kcm_sambaconf/sambafile.cpp | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/filesharing/advanced/kcm_sambaconf/sambafile.cpp b/filesharing/advanced/kcm_sambaconf/sambafile.cpp new file mode 100644 index 00000000..f1f48263 --- /dev/null +++ b/filesharing/advanced/kcm_sambaconf/sambafile.cpp @@ -0,0 +1,701 @@ +/* + Copyright (c) 2002-2004 Jan Schaefer <j_schaef@informatik.uni-kl.de> + + 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 <qfile.h> +#include <qprocess.h> +#include <qfileinfo.h> + +#include <ksimpleconfig.h> +#include <kdebug.h> +#include <qfileinfo.h> +#include <kio/job.h> +#include <kprocess.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <ktempfile.h> +#include <ksambashare.h> + +#include <pwd.h> +#include <time.h> +#include <unistd.h> + +#include "sambafile.h" + +#define FILESHARE_DEBUG 5009 + +SambaConfigFile::SambaConfigFile(SambaFile* sambaFile) +{ + QDict<QString>(10,false); + setAutoDelete(true); + _sambaFile = sambaFile; +} + +QString SambaConfigFile::getDefaultValue(const QString & name) +{ + SambaShare* defaults = _sambaFile->getTestParmValues(); + QString s = defaults->getValue(name,false,false); + + return s; +} + +SambaShare* SambaConfigFile::addShare(const QString & name) +{ + SambaShare* newShare = new SambaShare(name,this); + addShare(name,newShare); + return newShare; +} + + +void SambaConfigFile::addShare(const QString & name, SambaShare* share) +{ + insert(name,share), + _shareList.append(name); +} + +void SambaConfigFile::removeShare(const QString & name) +{ + remove(name); + _shareList.remove(name); +} + + +QStringList SambaConfigFile::getShareList() +{ + return _shareList; +} + +SambaFile::SambaFile(const QString & _path, bool _readonly) + : readonly(_readonly), + changed(false), + path(_path), + localPath(_path), + _sambaConfig(0), + _testParmValues(0), + _sambaVersion(-1), + _tempFile(0) +{ +} + +SambaFile::~SambaFile() +{ + delete _sambaConfig; + delete _testParmValues; + delete _tempFile; + +} + +bool SambaFile::isRemoteFile() { + return ! KURL(path).isLocalFile(); +} + +/** No descriptions */ +QString SambaFile::findShareByPath(const QString & path) const +{ + QDictIterator<SambaShare> it(*_sambaConfig); + KURL url(path); + url.adjustPath(-1); + + for ( ; it.current(); ++it ) + { + SambaShare* share = it.current(); + + QString *s = share->find("path"); + if (s) { + KURL curUrl(*s); + curUrl.adjustPath(-1); + + kdDebug(5009) << url.path() << " =? " << curUrl.path() << endl; + + if (url.path() == curUrl.path()) + return it.currentKey(); + } + } + + return QString::null; +} + +bool SambaFile::save() { + return slotApply(); +} + + +bool SambaFile::slotApply() +{ + if (readonly) { + kdDebug(FILESHARE_DEBUG) << "SambaFile::slotApply: readonly=true" << endl; + return false; + } + + // If we have write access to the smb.conf + // we simply save the values to it + // if not we have to save the results in + // a temporary file and copy it afterwards + // over the smb.conf file with kdesu. + if (QFileInfo(path).isWritable()) + { + saveTo(path); + changed = false; + return true; + } + + // Create a temporary smb.conf file + delete _tempFile; + _tempFile = new KTempFile(); + _tempFile->setAutoDelete(true); + + if (!saveTo(_tempFile->name())) { + kdDebug(5009) << "SambaFile::slotApply: Could not save to temporary file" << endl; + delete _tempFile; + _tempFile = 0; + return false; + } + + QFileInfo fi(path); + KURL url(path); + + if (KURL(path).isLocalFile()) { + KProcess proc; + kdDebug(5009) << "SambaFile::slotApply: is local file!" << endl; + + QString suCommand=QString("cp %1 %2; rm %3") + .arg(_tempFile->name()) + .arg(path) + .arg(_tempFile->name()); + proc << "kdesu" << "-d" << suCommand; + + if (! proc.start(KProcess::Block)) { + kdDebug(5009) << "SambaFile::slotApply: saving to " << path << " failed!" << endl; + //KMessageBox::sorry(0,i18n("Saving the results to %1 failed.").arg(path)); + delete _tempFile; + _tempFile = 0; + return false; + } + else { + changed = false; + delete _tempFile; + _tempFile = 0; + kdDebug(5009) << "SambaFile::slotApply: changes successfully saved!" << endl; + return true; + } + } else { + kdDebug(5009) << "SambaFile::slotApply: is remote file!" << endl; + _tempFile->setAutoDelete(true); + KURL srcURL; + srcURL.setPath( _tempFile->name() ); + + KIO::FileCopyJob * job = KIO::file_copy( srcURL, url, -1, true ); + connect( job, SIGNAL( result( KIO::Job * ) ), + this, SLOT( slotSaveJobFinished ( KIO::Job * ) ) ); + return (job->error()==0); + } + + return true; +} + + /** + * Returns a name which isn't already used for a share + **/ +QString SambaFile::getUnusedName(const QString alreadyUsedName) const +{ + + QString init = i18n("Unnamed"); + if (alreadyUsedName != QString::null) + init = alreadyUsedName; + + QString s = init; + + int i = 2; + + while (_sambaConfig->find(s)) + { + s = init+QString::number(i); + i++; + } + + return s; +} + + + +SambaShare* SambaFile::newShare(const QString & name) +{ + if (_sambaConfig->find(name)) + return 0L; + + SambaShare* share = new SambaShare(name,_sambaConfig); + _sambaConfig->addShare(name,share); + + changed = true; + + return share; + +} + +SambaShare* SambaFile::newShare(const QString & name, const QString & path) +{ + SambaShare* share = newShare(name); + if (share) + { + share->setValue("path",path); + } + + return share; +} + +SambaShare* SambaFile::newPrinter(const QString & name, const QString & printer) +{ + SambaShare* share = newShare(name); + + if (share) + { + share->setValue("printable",true); + share->setValue("printer name",printer); + } + + return share; +} + + +/** No descriptions */ +void SambaFile::removeShare(const QString & share) +{ + changed = true; + + _sambaConfig->removeShare(share); +} + +void SambaFile::removeShare(SambaShare* share) +{ + removeShare(share->getName()); +} + +void SambaFile::removeShareByPath(const QString & path) { + QString share = findShareByPath(path); + removeShare(share); +} + +/** No descriptions */ +SambaShare* SambaFile::getShare(const QString & share) const +{ + SambaShare *s = _sambaConfig->find(share); + + return s; +} + +/** +* Returns a list of all shared directories +**/ +SambaShareList* SambaFile::getSharedDirs() const +{ + SambaShareList* list = new SambaShareList(); + + QDictIterator<SambaShare> it(*_sambaConfig); + + for( ; it.current(); ++it ) + { + if (!it.current()->isPrinter() && + it.current()->getName() != "global") + { + list->append(it.current()); + } + } + + return list; +} + +/** +* Returns a list of all shared printers +**/ +SambaShareList* SambaFile::getSharedPrinters() const +{ + SambaShareList* list = new SambaShareList(); + + QDictIterator<SambaShare> it(*_sambaConfig); + + for( ; it.current(); ++it ) + { + if (it.current()->isPrinter()) + list->append(it.current()); + } + + return list; +} + +int SambaFile::getSambaVersion() { + if (_sambaVersion > -1) + return _sambaVersion; + + KProcess testParam; + testParam << "testparm"; + testParam << "-V"; + _parmOutput = QString(""); + _sambaVersion = 2; + + connect( &testParam, SIGNAL(receivedStdout(KProcess*,char*,int)), + this, SLOT(testParmStdOutReceived(KProcess*,char*,int))); + + + + if (testParam.start(KProcess::Block,KProcess::Stdout)) { + if (_parmOutput.find("3") > -1) + _sambaVersion = 3; + } + + kdDebug(5009) << "Samba version = " << _sambaVersion << endl; + + return _sambaVersion; +} + + +SambaShare* SambaFile::getTestParmValues(bool reload) +{ + if (_testParmValues && !reload) + return _testParmValues; + + + KProcess testParam; + testParam << "testparm"; + testParam << "-s"; + + if (getSambaVersion() == 3) + testParam << "-v"; + + + testParam << "/dev/null"; + _parmOutput = QString(""); + + connect( &testParam, SIGNAL(receivedStdout(KProcess*,char*,int)), + this, SLOT(testParmStdOutReceived(KProcess*,char*,int))); + + if (testParam.start(KProcess::Block,KProcess::Stdout)) + { + parseParmStdOutput(); + } else + _testParmValues = new SambaShare(_sambaConfig); + + return _testParmValues; +} + +void SambaFile::testParmStdOutReceived(KProcess *, char *buffer, int buflen) +{ + _parmOutput+=QString::fromLatin1(buffer,buflen); +} + +void SambaFile::parseParmStdOutput() +{ + + QTextIStream s(&_parmOutput); + + if (_testParmValues) + delete _testParmValues; + _testParmValues = new SambaShare(_sambaConfig); + + QString section=""; + + while (!s.atEnd()) + { + QString line = s.readLine().stripWhiteSpace(); + + // empty lines + if (line.isEmpty()) + continue; + + // comments + if ('#' == line[0]) + continue; + + // sections + if ('[' == line[0]) + { + // get the name of the section + section = line.mid(1,line.length()-2).lower(); + continue; + } + + // we are only interested in the global section + if (section != KGlobal::staticQString("global")) + continue; + + // parameter + // parameter + int i = line.find('='); + + if (i>-1) { + QString name = line.left(i).stripWhiteSpace(); + QString value = line.mid(i+1).stripWhiteSpace(); + _testParmValues->setValue(name,value,false,false); + } + + } + + + +} + +/** +* Try to find the samba config file position +* First tries the config file, then checks +* several common positions +* If nothing is found returns QString::null +**/ +QString SambaFile::findSambaConf() +{ + return KSambaShare::instance()->smbConfPath(); +} + +void SambaFile::slotSaveJobFinished( KIO::Job * job ) { + delete _tempFile; + _tempFile = 0; +} + +void SambaFile::slotJobFinished( KIO::Job * job ) +{ + if (job->error()) + emit canceled( job->errorString() ); + else + { + openFile(); + emit completed(); + } +} + +bool SambaFile::load() +{ + if (path.isNull() || path.isEmpty()) + return false; + + kdDebug(FILESHARE_DEBUG) << "SambaFile::load: path=" << path << endl; + KURL url(path); + + if (!url.isLocalFile()) { + KTempFile tempFile; + localPath = tempFile.name(); + KURL destURL; + destURL.setPath( localPath ); + KIO::FileCopyJob * job = KIO::file_copy( url, destURL, 0600, true, false, true ); +// emit started( d->m_job ); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotJobFinished ( KIO::Job * ) ) ); + return true; + } else { + localPath = path; + bool ret = openFile(); + if (ret) + emit completed(); + return ret; + } +} + +bool SambaFile::openFile() { + + QFile f(localPath); + + if (!f.open(IO_ReadOnly)) { + //throw SambaFileLoadException(QString("<qt>Could not open file <em>%1</em> for reading.</qt>").arg(path)); + return false; + } + + QTextStream s(&f); + + delete _sambaConfig; + + _sambaConfig = new SambaConfigFile(this); + + SambaShare *currentShare = 0L; + bool continuedLine = false; // is true if the line before ended with a backslash + QString completeLine; + QStringList comments; + + while (!s.eof()) + { + QString currentLine = s.readLine().stripWhiteSpace(); + + if (continuedLine) + { + completeLine += currentLine; + continuedLine = false; + } else + completeLine = currentLine; + + // is the line continued in the next line ? + if ( completeLine[completeLine.length()-1] == '\\' ) + { + continuedLine = true; + // remove the ending backslash + completeLine.truncate( completeLine.length()-1 ); + continue; + } + + // comments or empty lines + if (completeLine.isEmpty() || + '#' == completeLine[0] || + ';' == completeLine[0]) + { + comments.append(completeLine); + continue; + } + + + // sections + if ('[' == completeLine[0]) + { + // get the name of the section + QString section = completeLine.mid(1,completeLine.length()-2); + currentShare = _sambaConfig->addShare(section); + currentShare->setComments(comments); + comments.clear(); + + continue; + } + + // parameter + int i = completeLine.find('='); + + if (i>-1) + { + QString name = completeLine.left(i).stripWhiteSpace(); + QString value = completeLine.mid(i+1).stripWhiteSpace(); + + if (currentShare) + { + currentShare->setComments(name,comments); + currentShare->setValue(name,value,true,true); + + comments.clear(); + } + } + } + + f.close(); + + // Make sure there is a global share + if (!getShare("global")) { + _sambaConfig->addShare("global"); + } + + return true; +} + +bool SambaFile::saveTo(const QString & path) +{ + QFile f(path); + + if (!f.open(IO_WriteOnly)) + return false; + + QTextStream s(&f); + + QStringList shareList = _sambaConfig->getShareList(); + + for ( QStringList::Iterator it = shareList.begin(); it != shareList.end(); ++it ) + { + SambaShare* share = _sambaConfig->find(*it); + + // First add all comments of the share to the file + QStringList comments = share->getComments(); + for ( QStringList::Iterator cmtIt = comments.begin(); cmtIt != comments.end(); ++cmtIt ) + { + s << *cmtIt << endl; + + kdDebug(5009) << *cmtIt << endl; + } + + // If there are no lines before the section add + // a blank line + if (comments.isEmpty()) + s << endl; + + // Add the name of the share / section + s << "[" << share->getName() << "]" << endl; + + // Add all options of the share + QStringList optionList = share->getOptionList(); + + for ( QStringList::Iterator optionIt = optionList.begin(); optionIt != optionList.end(); ++optionIt ) + { + + // Add the comments of the option + comments = share->getComments(*optionIt); + for ( QStringList::Iterator cmtIt = comments.begin(); cmtIt != comments.end(); ++cmtIt ) + { + s << *cmtIt << endl; + } + + // Add the option + s << *optionIt << " = " << *share->find(*optionIt) << endl; + } + + + } + + f.close(); + + return true; +} + + +SambaConfigFile* SambaFile::getSambaConfigFile(KSimpleConfig* config) +{ + QStringList groups = config->groupList(); + + SambaConfigFile* samba = new SambaConfigFile(this); + + for ( QStringList::Iterator it = groups.begin(); it != groups.end(); ++it ) + { + QMap<QString,QString> entries = config->entryMap(*it); + + SambaShare *share = new SambaShare(*it,samba); + samba->insert(*it,share); + + for (QMap<QString,QString>::Iterator it2 = entries.begin(); it2 != entries.end(); ++it2 ) + { + if (!it2.data().isEmpty()) + share->setValue(it2.key(),QString(it2.data()),false,false); + } + + } + + return samba; + +} + +KSimpleConfig* SambaFile::getSimpleConfig(SambaConfigFile* sambaConfig, const QString & path) +{ + KSimpleConfig *config = new KSimpleConfig(path,false); + + QDictIterator<SambaShare> it(*sambaConfig); + + for ( ; it.current(); ++it ) + { + SambaShare* share = it.current(); + + config->setGroup(it.currentKey()); + + QDictIterator<QString> it2(*share); + + for (; it2.current(); ++it2 ) + { + config->writeEntry(it2.currentKey(), *it2.current()); + } + + } + + return config; +} + +#include "sambafile.moc" |