Properly handle whitespace in script paths
[quassel.git] / src / client / execwrapper.cpp
index 8ef8194..4958eb6 100644 (file)
@@ -32,22 +32,38 @@ ExecWrapper::ExecWrapper(QObject* parent) : QObject(parent) {
   connect(&_process, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus)));
   connect(&_process, SIGNAL(error(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError)));
 
-  connect(this, SIGNAL(stdout(QString)), SLOT(postStdout(QString)));
-  connect(this, SIGNAL(stderr(QString)), SLOT(postStderr(QString)));
+  connect(this, SIGNAL(output(QString)), SLOT(postStdout(QString)));
+  connect(this, SIGNAL(error(QString)), SLOT(postStderr(QString)));
 }
 
-void ExecWrapper::start(const BufferInfo &info, const QString &scriptName, const QStringList& params) {
+void ExecWrapper::start(const BufferInfo &info, const QString &command) {
   _bufferInfo = info;
-  _scriptName = scriptName;
-  foreach(QString scriptDir, Quassel::scriptDirPaths()) {
-    QString fileName = scriptDir + '/' + scriptName;
-    if(!QFile::exists(fileName))
-      continue;
-    _process.start(fileName, params);
-    return;
+  QString params;
+
+  QRegExp rx("^\\s*(\\S+)(\\s+(.*))?$");
+  if(!rx.exactMatch(command)) {
+    emit error(tr("Invalid command string for /exec: %1").arg(command));
+  } else {
+    _scriptName = rx.cap(1);
+    params = rx.cap(3);
   }
-  emit stderr(tr("Could not find script \"%1\"").arg(scriptName));
-  deleteLater();
+
+  // Make sure we don't execute something outside a script dir
+  if(_scriptName.contains("../") || _scriptName.contains("..\\"))
+    emit error(tr("Name \"%1\" is invalid: ../ or ..\\ are not allowed!").arg(_scriptName));
+
+  else {
+    foreach(QString scriptDir, Quassel::scriptDirPaths()) {
+      QString fileName = scriptDir + _scriptName;
+      if(!QFile::exists(fileName))
+        continue;
+      _process.start('"' + fileName + "\" " + params);
+      return;
+    }
+    emit error(tr("Could not find script \"%1\"").arg(_scriptName));
+  }
+
+  deleteLater(); // self-destruct
 }
 
 void ExecWrapper::postStdout(const QString &msg) {
@@ -62,32 +78,48 @@ void ExecWrapper::postStderr(const QString &msg) {
 
 void ExecWrapper::processFinished(int exitCode, QProcess::ExitStatus status) {
   if(status == QProcess::CrashExit) {
-    emit stderr(tr("Script \"%1\" crashed with exit code %2.").arg(_scriptName).arg(exitCode));
+    emit error(tr("Script \"%1\" crashed with exit code %2.").arg(_scriptName).arg(exitCode));
   }
 
-  // TODO empty buffers
+  // empty buffers
+  if(!_stdoutBuffer.isEmpty())
+    foreach(QString msg, _stdoutBuffer.split('\n'))
+      emit output(msg);
+  if(!_stderrBuffer.isEmpty())
+    foreach(QString msg, _stderrBuffer.split('\n'))
+    emit error(msg);
 
   deleteLater();
 }
 
-void ExecWrapper::processError(QProcess::ProcessError error) {
-  emit stderr(tr("Script \"%1\" caused error %2.").arg(_scriptName).arg(error));
+void ExecWrapper::processError(QProcess::ProcessError err) {
+  if(err == QProcess::FailedToStart)
+    emit error(tr("Script \"%1\" could not start.").arg(_scriptName));
+  else
+    emit error(tr("Script \"%1\" caused error %2.").arg(_scriptName).arg(err));
+
+  if(_process.state() != QProcess::Running)
+    deleteLater();
 }
 
 void ExecWrapper::processReadStdout() {
-  _stdoutBuffer.append(_process.readAllStandardOutput());
+  QString str = QTextCodec::codecForLocale()->toUnicode(_process.readAllStandardOutput());
+  str.replace(QRegExp("\r\n?"), "\n");
+  _stdoutBuffer.append(str);
   int idx;
   while((idx = _stdoutBuffer.indexOf('\n')) >= 0) {
-    emit stdout(_stdoutBuffer.left(idx));
+    emit output(_stdoutBuffer.left(idx));
     _stdoutBuffer = _stdoutBuffer.mid(idx + 1);
   }
 }
 
 void ExecWrapper::processReadStderr() {
-  _stderrBuffer.append(_process.readAllStandardError());
+  QString str = QTextCodec::codecForLocale()->toUnicode(_process.readAllStandardError());
+  str.replace(QRegExp("\r\n?"), "\n");
+  _stderrBuffer.append(str);
   int idx;
   while((idx = _stderrBuffer.indexOf('\n')) >= 0) {
-    emit stdout(_stderrBuffer.left(idx));
+    emit error(_stderrBuffer.left(idx));
     _stderrBuffer = _stderrBuffer.mid(idx + 1);
   }
 }