aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornils <nils@34ebc366-c3a9-4b3c-9f84-69acf7962910>2012-08-02 00:05:44 +0000
committernils <nils@34ebc366-c3a9-4b3c-9f84-69acf7962910>2012-08-02 00:05:44 +0000
commit4149c8712b45791605ea3502c00baa94b0948f33 (patch)
treee3e9d021b5d8e73a36ed5b2fda48b0fe2dc81e38
parentstart removing gpgme (diff)
downloadgpg4usb-4149c8712b45791605ea3502c00baa94b0948f33.tar.gz
gpg4usb-4149c8712b45791605ea3502c00baa94b0948f33.zip
try to integrate gpg wrapper from kgpg - broken now
git-svn-id: http://cpunk.de/svn/src/gpg4usb/branches/0.3.2-mac@921 34ebc366-c3a9-4b3c-9f84-69acf7962910
-rw-r--r--gpg4usb.pro18
-rw-r--r--gpgcontext.cpp33
-rw-r--r--gpgcontext.h3
-rw-r--r--kgpg/gpgproc.cpp348
-rw-r--r--kgpg/gpgproc.h156
-rw-r--r--kgpg/kgpg.pro12
-rw-r--r--kgpg/klinebufferedprocess.cpp112
-rw-r--r--kgpg/klinebufferedprocess.h155
-rw-r--r--kgpg/kprocess.cpp410
-rw-r--r--kgpg/kprocess.h341
-rw-r--r--kgpg/kprocess_p.h50
11 files changed, 1623 insertions, 15 deletions
diff --git a/gpg4usb.pro b/gpg4usb.pro
index d621071..f8f9ace 100644
--- a/gpg4usb.pro
+++ b/gpg4usb.pro
@@ -15,6 +15,7 @@ INCLUDEPATH += . \
CONFIG += release static
#CONFIG += release
+#CONFIG += debug
QT += network
# Input
HEADERS += attachments.h \
@@ -39,7 +40,10 @@ HEADERS += attachments.h \
verifykeydetailbox.h \
wizard.h \
helppage.h \
-# gpgproc.h \
+ kgpg/gpgproc.h \
+ kgpg/klinebufferedprocess.h \
+ kgpg/kprocess.h \
+ kgpg/kprocess_p.h \
gpgconstants.h
SOURCES += attachments.cpp \
@@ -65,7 +69,9 @@ SOURCES += attachments.cpp \
verifykeydetailbox.cpp \
wizard.cpp \
helppage.cpp \
-# gpgproc.cpp \
+ kgpg/gpgproc.cpp \
+ kgpg/klinebufferedprocess.cpp \
+ kgpg/kprocess.cpp \
gpgconstants.cpp
RC_FILE = gpg4usb.rc
@@ -73,12 +79,12 @@ RC_FILE = gpg4usb.rc
RESOURCES = gpg4usb.qrc
# comment out line below for static building
-#LIBS += -lgpgme \
-# -lgpg-error \
+LIBS += -lgpgme \
+ -lgpg-error \
# comment in for static buildding in windows
-INCLUDEPATH += ./macbuild/include
-LIBS +=./macbuild/lib/libgpgme.a ./macbuild/lib/libgpg-error.a
+#INCLUDEPATH += ./macbuild/include
+#LIBS +=./macbuild/lib/libgpgme.a ./macbuild/lib/libgpg-error.a
DEFINES += _FILE_OFFSET_BITS=64
diff --git a/gpgcontext.cpp b/gpgcontext.cpp
index 251d372..534ddea 100644
--- a/gpgcontext.cpp
+++ b/gpgcontext.cpp
@@ -20,7 +20,8 @@
*/
#include "gpgcontext.h"
-
+#include "kgpg/gpgproc.h"
+#include "kgpg/klinebufferedprocess.h"
#ifdef _WIN32
#include <windows.h>
#include <unistd.h> /* contains read/write */
@@ -43,33 +44,33 @@ GpgContext::GpgContext()
* subsystem in GPGME. (from the info page) */
#ifdef Q_WS_WIN
- QString gpgBin = appPath + "/bin/gpg.exe";
- QString gpgKeys = appPath + "/keydb";
+ gpgBin = appPath + "/bin/gpg.exe";
+ gpgKeys = appPath + "/keydb";
#endif
#ifdef Q_WS_MAC
- QString gpgBin = appPath + "/bin/gpg-mac.app";
+ gpgBin = appPath + "/bin/gpg-mac.app";
- QString gpgKeys = appPath + "/keydb";
+ gpgKeys = appPath + "/keydb";
qDebug() << "gpg bin:" << gpgBin;
qDebug() << "gpg keydb: " << gpgKeys;
#endif
#ifdef Q_WS_X11
- QString gpgBin = appPath + "/bin/gpg";
- QString gpgKeys = appPath + "/keydb";
+ gpgBin = appPath + "/bin/gpg";
+ gpgKeys = appPath + "/keydb";
#endif
QStringList args;
args << "--homedir" << gpgKeys << "--list-keys";
- QProcess gpg;
+/* QProcess gpg;
gpg.setProcessChannelMode(QProcess::MergedChannels);
gpg.start(gpgBin, args);
gpg.waitForFinished(-1);
qDebug() << "huhu" << gpg.readAll();
-
+*/
connect(this,SIGNAL(keyDBChanged()),this,SLOT(refreshKeyList()));
refreshKeyList();
}
@@ -211,6 +212,20 @@ GpgKeyList GpgContext::listKeys()
GpgKeyList keys;
+ GPGProc process(this, gpgBin);
+/* process <<
+ QLatin1String("--with-colons") <<
+ QLatin1String("--with-fingerprint") <<
+ QLatin1String("--fixed-list-mode") <<
+ QLatin1String("--list-keys");
+
+ process.setOutputChannelMode(KProcess::MergedChannels);
+
+ process.start();
+ process.waitForFinished(-1);*/
+ //while (item == process->)
+// return readPublicKeysProcess(process, NULL);
+
//TODO dont run the loop more often than necessary
// list all keys ( the 0 is for all )
diff --git a/gpgcontext.h b/gpgcontext.h
index 4efc3fe..f9caf61 100644
--- a/gpgcontext.h
+++ b/gpgcontext.h
@@ -176,6 +176,9 @@ private:
QByteArray *stdOut,
QByteArray *stdErr);
+ QString gpgBin;
+ QString gpgKeys;
+
};
} // namespace GpgME
diff --git a/kgpg/gpgproc.cpp b/kgpg/gpgproc.cpp
new file mode 100644
index 0000000..291e8a2
--- /dev/null
+++ b/kgpg/gpgproc.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010,2011,2012 Rolf Eike Beer <[email protected]>
+ */
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "gpgproc.h"
+
+//#include "kgpgsettings.h"
+
+//#include <KDebug>
+#include <QDebug>
+//#include <KProcess>
+#include "kprocess.h"
+//#include <KStandardDirs>
+#include <QDir>
+#include <QTextCodec>
+
+class GnupgBinary {
+public:
+ GnupgBinary();
+
+ const QString &binary() const;
+ void setBinary(const QString &executable);
+ const QStringList &standardArguments() const;
+ unsigned int version() const;
+ bool supportsDebugLevel() const;
+
+private:
+ QString m_binary;
+ QStringList m_standardArguments;
+ unsigned int m_version;
+ bool m_useDebugLevel;
+};
+
+GnupgBinary::GnupgBinary()
+ : m_useDebugLevel(false)
+{
+}
+
+const QString &GnupgBinary::binary() const
+{
+ return m_binary;
+}
+
+/**
+ * @brief check if GnuPG returns an error for this arguments
+ * @param executable the GnuPG executable to call
+ * @param arguments the arguments to pass to executable
+ *
+ * The arguments will be used together with "--version", so they should not
+ * be any commands.
+ */
+static bool checkGnupgArguments(const QString &executable, const QStringList &arguments)
+{
+ KProcess gpg;
+
+ // We ignore the output anyway, just make sure it doesn't clutter the output of
+ // the parent process. Simplify the handling by putting all trash in one can.
+ gpg.setOutputChannelMode(KProcess::MergedChannels);
+
+ QStringList allArguments = arguments;
+ allArguments << QLatin1String("--version");
+ gpg.setProgram(executable, allArguments);
+
+ return (gpg.execute() == 0);
+}
+
+static QString getGpgProcessHome(const QString &binary)
+{
+ GPGProc process(0, binary);
+ process << QLatin1String( "--version" );
+ process.start();
+ process.waitForFinished(-1);
+
+ if (process.exitCode() == 255) {
+ return QString();
+ }
+
+ QString line;
+ while (process.readln(line) != -1) {
+ if (line.startsWith(QLatin1String("Home: "))) {
+ line.remove(0, 6);
+ return line;
+ }
+ }
+
+ return QString();
+}
+
+
+void GnupgBinary::setBinary(const QString &executable)
+{
+ qDebug() << "checking version of GnuPG executable" << executable;
+ // must be set first as gpgVersionString() uses GPGProc to parse the output
+ m_binary = executable;
+ const QString verstr = GPGProc::gpgVersionString(executable);
+ m_version = GPGProc::gpgVersion(verstr);
+ qDebug() << "version is" << verstr << m_version;
+
+ m_useDebugLevel = (m_version > 0x20000);
+
+ const QString gpgConfigFile = "";//KGpgSettings::gpgConfigPath();
+
+ m_standardArguments.clear();
+ m_standardArguments << QLatin1String( "--no-secmem-warning" )
+ << QLatin1String( "--no-tty" )
+ << QLatin1String("--no-greeting");
+
+ if (!gpgConfigFile.isEmpty())
+ m_standardArguments << QLatin1String("--options")
+ << gpgConfigFile;
+
+ QStringList debugLevelArguments(QLatin1String("--debug-level"));
+ debugLevelArguments << QLatin1String("none");
+ if (checkGnupgArguments(executable, debugLevelArguments))
+ m_standardArguments << debugLevelArguments;
+}
+
+const QStringList& GnupgBinary::standardArguments() const
+{
+ return m_standardArguments;
+}
+
+unsigned int GnupgBinary::version() const
+{
+ return m_version;
+}
+
+bool GnupgBinary::supportsDebugLevel() const
+{
+ return m_useDebugLevel;
+}
+
+Q_GLOBAL_STATIC(GnupgBinary, lastBinary)
+
+GPGProc::GPGProc(QObject *parent, const QString &binary)
+ : KLineBufferedProcess(parent)
+{
+ resetProcess(binary);
+}
+
+GPGProc::~GPGProc()
+{
+}
+
+void
+GPGProc::resetProcess(const QString &binary)
+{
+ GnupgBinary *bin;// = lastBinary;
+ QString executable;
+
+ qDebug() << "bin:" << binary;
+
+ /*if (binary.isEmpty())
+ executable = KGpgSettings::gpgBinaryPath();
+ else*/
+ executable = binary;
+
+ if (bin->binary() != executable)
+ bin->setBinary(executable);
+
+ setProgram(executable, bin->standardArguments());
+
+ setOutputChannelMode(OnlyStdoutChannel);
+
+ disconnect(SIGNAL(finished(int,QProcess::ExitStatus)));
+ disconnect(SIGNAL(lineReadyStandardOutput()));
+}
+
+void GPGProc::start()
+{
+ // make sure there is exactly one connection from us to that signal
+ connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished()), Qt::UniqueConnection);
+ connect(this, SIGNAL(lineReadyStandardOutput()), this, SLOT(received()), Qt::UniqueConnection);
+ KProcess::start();
+}
+
+void GPGProc::received()
+{
+ emit readReady();
+}
+
+void GPGProc::finished()
+{
+ emit processExited();
+}
+
+int GPGProc::readln(QString &line, const bool colons)
+{
+ QByteArray a;
+ if (!readLineStandardOutput(&a))
+ return -1;
+
+ line = recode(a, colons);
+
+ return line.length();
+}
+
+int GPGProc::readln(QStringList &l)
+{
+ QString s;
+
+ int len = readln(s);
+ if (len < 0)
+ return len;
+
+ l = s.split(QLatin1Char( ':' ));
+
+ for (int i = 0; i < l.count(); ++i)
+ {
+ int j = 0;
+ while ((j = l[i].indexOf(QLatin1String( "\\x3a" ), j, Qt::CaseInsensitive)) >= 0)
+ {
+ l[i].replace(j, 4, QLatin1Char( ':' ));
+ j++;
+ }
+ }
+
+ return l.count();
+}
+
+QString
+GPGProc::recode(QByteArray a, const bool colons)
+{
+ int pos = 0;
+
+ while ((pos = a.indexOf("\\x", pos)) >= 0) {
+ if (pos > a.length() - 4)
+ break;
+
+ const QByteArray pattern(a.mid(pos, 4));
+ const QByteArray hexnum(pattern.right(2));
+ bool ok;
+ char n[2];
+ n[0] = hexnum.toUShort(&ok, 16);
+ n[1] = '\0'; // to use n as a 0-terminated string
+ if (!ok)
+ continue;
+
+ // QLatin1Char( ':' ) must be skipped, it is used as column delimiter
+ // since it is pure ascii it can be replaced in QString.
+ if (!colons && (n[0] == ':' )) {
+ pos += 3;
+ continue;
+ }
+
+ // it is likely to find the same byte sequence more than once
+ int npos = pos;
+ do {
+ a.replace(npos, 4, n);
+ } while ((npos = a.indexOf(pattern, npos)) >= 0);
+ }
+
+ return QTextCodec::codecForName("utf8")->toUnicode(a);
+}
+
+int GPGProc::gpgVersion(const QString &vstr)
+{
+ if (vstr.isEmpty())
+ return -1;
+
+ QStringList values(vstr.split(QLatin1Char( '.' )));
+ if (values.count() < 3)
+ return -2;
+
+ return (0x10000 * values[0].toInt() + 0x100 * values[1].toInt() + values[2].toInt());
+}
+
+QString GPGProc::gpgVersionString(const QString &binary)
+{
+ GPGProc process(0, binary);
+ process << QLatin1String( "--version" );
+ process.start();
+ process.waitForFinished(-1);
+
+ if (process.exitCode() == 255)
+ return QString();
+
+ QString line;
+ if (process.readln(line) != -1)
+ return line.simplified().section(QLatin1Char( ' ' ), -1);
+ else
+ return QString();
+}
+
+QString GPGProc::getGpgStartupError(const QString &binary)
+{
+ GPGProc process(0, binary);
+ process << QLatin1String( "--version" );
+ process.start();
+ process.waitForFinished(-1);
+
+ QString result;
+
+ while (process.hasLineStandardError()) {
+ QByteArray tmp;
+ process.readLineStandardError(&tmp);
+ tmp += '\n';
+ result += QString::fromUtf8(tmp);
+ }
+
+ return result;
+}
+
+QString GPGProc::getGpgHome(const QString &binary)
+{
+ // First try: if environment is set GnuPG will use that directory
+ // We can use this directly without starting a new process
+ QByteArray env(qgetenv("GNUPGHOME"));
+ QString gpgHome;
+ if (!env.isEmpty()) {
+ gpgHome = QLatin1String( env );
+ } else if (!binary.isEmpty()) {
+ // Second try: start GnuPG and ask what it is
+ gpgHome = getGpgProcessHome(binary);
+ }
+
+ // Third try: guess what it is.
+ if (gpgHome.isEmpty()) {
+#ifdef Q_OS_WIN32 //krazy:exclude=cpp
+ gpgHome = qgetenv("APPDATA") + QLatin1String( "/gnupg/" );
+ gpgHome.replace(QLatin1Char( '\\' ), QLatin1Char( '/' ));
+#else
+ gpgHome = QDir::homePath() + QLatin1String( "/.gnupg/" );
+#endif
+ }
+
+ gpgHome.replace(QLatin1String( "//" ), QLatin1String( "/" ));
+
+ if (!gpgHome.endsWith(QLatin1Char( '/' )))
+ gpgHome.append(QLatin1Char( '/' ));
+
+ if (gpgHome.startsWith(QLatin1Char( '~' )))
+ gpgHome.replace(0, 1, QDir::homePath());
+
+ //KStandardDirs::makeDir(gpgHome, 0700);
+ return gpgHome;
+}
+
+//#include "gpgproc.moc"
diff --git a/kgpg/gpgproc.h b/kgpg/gpgproc.h
new file mode 100644
index 0000000..ce868db
--- /dev/null
+++ b/kgpg/gpgproc.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2007 Rolf Eike Beer <[email protected]>
+ */
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+#ifndef GPGPROC_H
+#define GPGPROC_H
+
+#include <QString>
+#include <QStringList>
+
+#include "klinebufferedprocess.h"
+
+/**
+ * @brief A interface to GnuPG handling UTF8 recoding correctly
+ *
+ * This class handles the GnuPG formatted UTF8 output correctly.
+ * GnuPG recodes some characters as \\xnn where nn is the hex representation
+ * of the character. This can't be fixed up simply when using QString as
+ * QString already did it's own UTF8 conversion. Therefore we replace this
+ * sequences by their corresponding character so QString will work just fine.
+ *
+ * As we know that GnuPG limits it's columns by QLatin1Char( ':' ) we skip \\x3a. Since this
+ * is an ascii character (single byte) the replacement can be done later without
+ * problems after the line has been split into pieces.
+ *
+ * @author Rolf Eike Beer
+ */
+class GPGProc : public KLineBufferedProcess
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ * @param parent parent object
+ * @param binary path to GnuPG binary or QString() to use the configured
+ */
+ explicit GPGProc(QObject *parent = 0, const QString &binary = QString());
+
+ /**
+ * Destructor
+ */
+ ~GPGProc();
+
+ /**
+ * Starts the process
+ */
+ void start();
+
+ /**
+ * Reads a line of text (excluding '\\n').
+ *
+ * Use readln() in response to a readReady() signal.
+ * You may use it multiple times if more than one line of data is
+ * available.
+ *
+ * readln() never blocks.
+ *
+ * @param line is used to store the line that was read.
+ * @param colons recode also colons
+ * @return the number of characters read, or -1 if no data is available.
+ */
+ int readln(QString &line, const bool colons = false);
+
+ /**
+ * Reads a line of text and splits it into parts.
+ *
+ * Use readln() in response to a readReady() signal.
+ * You may use it multiple times if more than one line of data is
+ * available.
+ *
+ * readln() never blocks.
+ *
+ * @param l is used to store the parts of the line that was read.
+ * @return the number of characters read, or -1 if no data is available.
+ */
+ int readln(QStringList &l);
+
+ /**
+ * Recode a line from GnuPG encoding to UTF8
+ *
+ * @param a data to recode
+ * @param colons recode also colons
+ * @return recoded string
+ */
+ static QString recode(QByteArray a, const bool colons = true);
+
+ /**
+ * Reset the class to the state it had right after creation
+ * @param binary path to GnuPG binary or empty string to use the configured one
+ */
+ void resetProcess(const QString &binary = QString());
+
+ /**
+ * @brief parse GnuPG version string and return version as number
+ * @param vstr version string
+ * @return -1 if vstr is empty, -2 on parse error, parsed number on success
+ *
+ * The version string must be in format A.B.C with A, B, and C numbers. The
+ * returned number is A * 65536 + B * 256 + C.
+ */
+ static int gpgVersion(const QString &vstr);
+ /**
+ * @brief get the GnuPG version string of the given binary
+ * @param binary name or path to GnuPG binary
+ * @return version string or empty string on error
+ *
+ * This starts a GnuPG process and asks the binary for version information.
+ * The returned string is the version information without any leading text.
+ */
+ static QString gpgVersionString(const QString &binary);
+ /**
+ * @brief find users GnuPG directory
+ * @param binary name or path to GnuPG binary
+ * @return path to directory
+ *
+ * Use this function to find out where GnuPG would store it's configuration
+ * and data files. The returned path always ends with a '/'.
+ */
+ static QString getGpgHome(const QString &binary);
+
+ /**
+ * @brief run GnuPG and check if it complains about anything
+ * @param binary the GnuPG binary to run
+ * @return the error message GnuPG gave out (if any)
+ */
+ static QString getGpgStartupError(const QString &binary);
+
+signals:
+ /**
+ * Emitted when the process is ready for reading.
+ * The signal is only emitted if at least one complete line of data is ready.
+ * @param p the process that emitted the signal
+ */
+ void readReady();
+
+ /**
+ * Emitted when the process has finished
+ * @param p the process that emitted the signal
+ */
+ void processExited();
+
+protected slots:
+ void finished();
+ void received();
+};
+
+#endif // GPGPROC_H
diff --git a/kgpg/kgpg.pro b/kgpg/kgpg.pro
new file mode 100644
index 0000000..7dd6391
--- /dev/null
+++ b/kgpg/kgpg.pro
@@ -0,0 +1,12 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Wed Aug 1 23:46:35 2012
+######################################################################
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+HEADERS += gpgproc.h klinebufferedprocess.h kprocess.h kprocess_p.h
+SOURCES += gpgproc.cpp klinebufferedprocess.cpp kprocess.cpp
diff --git a/kgpg/klinebufferedprocess.cpp b/kgpg/klinebufferedprocess.cpp
new file mode 100644
index 0000000..00099af
--- /dev/null
+++ b/kgpg/klinebufferedprocess.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 Rolf Eike Beer <[email protected]>
+ */
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "klinebufferedprocess.h"
+
+
+KLineBufferedProcessPrivate::KLineBufferedProcessPrivate(KLineBufferedProcess *parent)
+ : m_newlineInStdout(-1),
+ m_newlineInStderr(-1),
+ m_parent(parent),
+#ifdef Q_OS_WIN32 //krazy:exclude=cpp
+ m_lineEnd("\r\n")
+#else
+ m_lineEnd("\n")
+#endif
+{
+}
+
+KLineBufferedProcess::KLineBufferedProcess(QObject *parent)
+ : KProcess(parent),
+ d(new KLineBufferedProcessPrivate(this))
+{
+ connect(this, SIGNAL(readyReadStandardOutput()), this, SLOT(_k_receivedStdout()));
+ connect(this, SIGNAL(readyReadStandardError()), this, SLOT(_k_receivedStderr()));
+}
+
+KLineBufferedProcess::~KLineBufferedProcess()
+{
+ delete d;
+}
+
+void KLineBufferedProcessPrivate::_k_receivedStdout()
+{
+ QByteArray ndata = m_parent->readAllStandardOutput();
+ int oldBufferSize = m_stdoutBuffer.size();
+ m_stdoutBuffer.append(ndata);
+
+ if (m_newlineInStdout < 0) {
+ m_newlineInStdout = ndata.indexOf(m_lineEnd);
+ if (m_newlineInStdout >= 0) {
+ m_newlineInStdout += oldBufferSize;
+ emit m_parent->lineReadyStandardOutput();
+ }
+ }
+}
+
+void KLineBufferedProcessPrivate::_k_receivedStderr()
+{
+ QByteArray ndata = m_parent->readAllStandardError();
+ int oldBufferSize = m_stderrBuffer.size();
+ m_stderrBuffer.append(ndata);
+
+ if (m_newlineInStderr < 0) {
+ m_newlineInStderr = ndata.indexOf(m_lineEnd);
+ if (m_newlineInStderr >= 0) {
+ m_newlineInStderr += oldBufferSize;
+ emit m_parent->lineReadyStandardError();
+ }
+ }
+}
+
+bool KLineBufferedProcess::readLineStandardOutput(QByteArray *line)
+{
+ if (d->m_newlineInStdout < 0) {
+ return false;
+ }
+
+ // don't copy '\n'
+ *line = d->m_stdoutBuffer.left(d->m_newlineInStdout);
+ d->m_stdoutBuffer.remove(0, d->m_newlineInStdout + d->m_lineEnd.length());
+
+ d->m_newlineInStdout = d->m_stdoutBuffer.indexOf(d->m_lineEnd);
+
+ return true;
+}
+
+bool KLineBufferedProcess::readLineStandardError(QByteArray *line)
+{
+ if (d->m_newlineInStderr < 0) {
+ return false;
+ }
+
+ // don't copy '\n'
+ *line = d->m_stderrBuffer.left(d->m_newlineInStderr);
+ d->m_stderrBuffer.remove(0, d->m_newlineInStderr + d->m_lineEnd.length());
+
+ d->m_newlineInStderr = d->m_stderrBuffer.indexOf(d->m_lineEnd);
+
+ return true;
+}
+
+bool KLineBufferedProcess::hasLineStandardOutput() const
+{
+ return d->m_newlineInStdout >= 0;
+}
+
+bool KLineBufferedProcess::hasLineStandardError() const
+{
+ return d->m_newlineInStderr >= 0;
+}
+
+//#include "moc_klinebufferedprocess.cpp"
diff --git a/kgpg/klinebufferedprocess.h b/kgpg/klinebufferedprocess.h
new file mode 100644
index 0000000..eab360b
--- /dev/null
+++ b/kgpg/klinebufferedprocess.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2008 Rolf Eike Beer <[email protected]>
+ */
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KLINEBUFFEREDPROCESS_H
+#define KLINEBUFFEREDPROCESS_H
+
+#include "kprocess.h"
+
+class QByteArray;
+//class KLineBufferedProcessPrivate;
+class KLineBufferedProcess;
+class KLineBufferedProcessPrivate
+{
+public:
+ KLineBufferedProcessPrivate(KLineBufferedProcess *parent);
+
+//private slot implementations
+ void _k_receivedStdout();
+ void _k_receivedStderr();
+
+ QByteArray m_stdoutBuffer;
+ QByteArray m_stderrBuffer;
+ int m_newlineInStdout;
+ int m_newlineInStderr;
+ KLineBufferedProcess * const m_parent;
+ const QByteArray m_lineEnd;
+};
+
+/**
+ * Read output of a process split into lines
+ *
+ * This class reads the output of a process and splits it up into lines. This
+ * is especially useful if you try to parse the output of a command line tool.
+ *
+ * \b Usage \n
+ *
+ * The class is created and set up like a KProcess. After this you can do
+ * something like this:
+ *
+ * \code
+ * connect(m_linebufprocess, SIGNAL(lineReadyStandardOutput()), SLOT(dataStdout()));
+ * ...
+ * void myobj::dataStdout()
+ * {
+ * while (m_linebufprocess->hasLineStandardOutput()) {
+ * QByteArray line;
+ * m_linebufprocess->readLineStandardOutput(line);
+ * ...
+ * }
+ * }
+ * \endcode
+ *
+ * Never use the read functionality of KProcess with this class. This class
+ * needs to read all data from the process into an internal buffer first. If
+ * you try to use the read functions of the parent classes you would normally
+ * get no output at all.
+ *
+ * The write functions of the parent classes are not effected. You can use
+ * them exactly the same way as in KProcess.
+ *
+ * @author Rolf Eike Beer
+ */
+class KLineBufferedProcess : public KProcess
+{
+ Q_OBJECT
+ friend class KLineBufferedProcessPrivate;
+
+public:
+ /**
+ * Constructor
+ */
+ explicit KLineBufferedProcess(QObject *parent = 0);
+
+ /**
+ * Destructor
+ */
+ ~KLineBufferedProcess();
+
+ /**
+ * Reads a line of text (excluding '\\n') from stdout.
+ *
+ * Use readLineStdout() in response to a lineReadyStdout() signal or
+ * when hasLineStdout() returns true. You may use it multiple times if
+ * more than one line of data is available. If no complete line is
+ * available the content of line is undefined and the function returns
+ * false.
+ *
+ * @param line is used to store the line that was read.
+ * @return if data was read or not
+ */
+ bool readLineStandardOutput(QByteArray *line);
+
+ /**
+ * Reads a line of text (excluding '\\n') from stderr.
+ *
+ * Use readLineStderr() in response to a lineReadyStderr() signal or
+ * when hasLineStderr() returns true. You may use it multiple times if
+ * more than one line of data is available. If no complete line is
+ * available the content of line is undefined and the function returns
+ * false.
+ *
+ * @param line is used to store the line that was read.
+ * @return if data was read or not
+ */
+ bool readLineStandardError(QByteArray *line);
+
+ /**
+ * Checks if a line is ready on stdout
+ *
+ * @return true if a complete line can be read
+ */
+ bool hasLineStandardOutput() const;
+
+ /**
+ * Checks if a line is ready on stdout
+ *
+ * @return true if a complete line can be read
+ */
+ bool hasLineStandardError() const;
+
+signals:
+ /**
+ * Emitted when there is a line of data available from stdout when there was
+ * previously none.
+ * There may or may not be more than one line available for reading when this
+ * signal is emitted.
+ */
+ void lineReadyStandardOutput();
+
+ /**
+ * Emitted when there is a line of data available from stderr when there was
+ * previously none.
+ * There may or may not be more than one line available for reading when this
+ * signal is emitted.
+ */
+ void lineReadyStandardError();
+
+private:
+ KLineBufferedProcessPrivate* const d;
+
+ Q_PRIVATE_SLOT(d, void _k_receivedStdout())
+ Q_PRIVATE_SLOT(d, void _k_receivedStderr())
+};
+
+#endif // KLINEBUFFEREDPROCESS_H
diff --git a/kgpg/kprocess.cpp b/kgpg/kprocess.cpp
new file mode 100644
index 0000000..a5b8628
--- /dev/null
+++ b/kgpg/kprocess.cpp
@@ -0,0 +1,410 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (C) 2007 Oswald Buddenhagen <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kprocess_p.h"
+
+//#include <kstandarddirs.h>
+//#include <kshell.h>
+//#ifdef Q_OS_WIN
+//# include <kshell_p.h>
+//#endif
+
+#include <qfile.h>
+
+#ifdef Q_OS_WIN
+# include <windows.h>
+#else
+# include <unistd.h>
+# include <errno.h>
+#endif
+
+#ifndef Q_OS_WIN
+# define STD_OUTPUT_HANDLE 1
+# define STD_ERROR_HANDLE 2
+#endif
+
+#ifdef _WIN32_WCE
+#include <stdio.h>
+#endif
+
+void KProcessPrivate::writeAll(const QByteArray &buf, int fd)
+{
+#ifdef Q_OS_WIN
+#ifndef _WIN32_WCE
+ HANDLE h = GetStdHandle(fd);
+ if (h) {
+ DWORD wr;
+ WriteFile(h, buf.data(), buf.size(), &wr, 0);
+ }
+#else
+ fwrite(buf.data(), 1, buf.size(), (FILE*)fd);
+#endif
+#else
+ int off = 0;
+ do {
+ int ret = ::write(fd, buf.data() + off, buf.size() - off);
+ if (ret < 0) {
+ if (errno != EINTR)
+ return;
+ } else {
+ off += ret;
+ }
+ } while (off < buf.size());
+#endif
+}
+
+void KProcessPrivate::forwardStd(KProcess::ProcessChannel good, int fd)
+{
+ Q_Q(KProcess);
+
+ QProcess::ProcessChannel oc = q->readChannel();
+ q->setReadChannel(good);
+ writeAll(q->readAll(), fd);
+ q->setReadChannel(oc);
+}
+
+void KProcessPrivate::_k_forwardStdout()
+{
+#ifndef _WIN32_WCE
+ forwardStd(KProcess::StandardOutput, STD_OUTPUT_HANDLE);
+#else
+ forwardStd(KProcess::StandardOutput, (int)stdout);
+#endif
+}
+
+void KProcessPrivate::_k_forwardStderr()
+{
+#ifndef _WIN32_WCE
+ forwardStd(KProcess::StandardError, STD_ERROR_HANDLE);
+#else
+ forwardStd(KProcess::StandardError, (int)stderr);
+#endif
+}
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KProcess::KProcess(QObject *parent) :
+ QProcess(parent),
+ d_ptr(new KProcessPrivate)
+{
+ d_ptr->q_ptr = this;
+ setOutputChannelMode(ForwardedChannels);
+}
+
+KProcess::KProcess(KProcessPrivate *d, QObject *parent) :
+ QProcess(parent),
+ d_ptr(d)
+{
+ d_ptr->q_ptr = this;
+ setOutputChannelMode(ForwardedChannels);
+}
+
+KProcess::~KProcess()
+{
+ delete d_ptr;
+}
+
+void KProcess::setOutputChannelMode(OutputChannelMode mode)
+{
+ Q_D(KProcess);
+
+ d->outputChannelMode = mode;
+ disconnect(this, SIGNAL(readyReadStandardOutput()));
+ disconnect(this, SIGNAL(readyReadStandardError()));
+ switch (mode) {
+ case OnlyStdoutChannel:
+ connect(this, SIGNAL(readyReadStandardError()), SLOT(_k_forwardStderr()));
+ break;
+ case OnlyStderrChannel:
+ connect(this, SIGNAL(readyReadStandardOutput()), SLOT(_k_forwardStdout()));
+ break;
+ default:
+ QProcess::setProcessChannelMode((ProcessChannelMode)mode);
+ return;
+ }
+ QProcess::setProcessChannelMode(QProcess::SeparateChannels);
+}
+
+KProcess::OutputChannelMode KProcess::outputChannelMode() const
+{
+ Q_D(const KProcess);
+
+ return d->outputChannelMode;
+}
+
+void KProcess::setNextOpenMode(QIODevice::OpenMode mode)
+{
+ Q_D(KProcess);
+
+ d->openMode = mode;
+}
+
+#define DUMMYENV "_KPROCESS_DUMMY_="
+
+void KProcess::clearEnvironment()
+{
+ setEnvironment(QStringList() << QString::fromLatin1(DUMMYENV));
+}
+
+void KProcess::setEnv(const QString &name, const QString &value, bool overwrite)
+{
+ QStringList env = environment();
+ if (env.isEmpty()) {
+ env = systemEnvironment();
+ env.removeAll(QString::fromLatin1(DUMMYENV));
+ }
+ QString fname(name);
+ fname.append(QLatin1Char('='));
+ for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
+ if ((*it).startsWith(fname)) {
+ if (overwrite) {
+ *it = fname.append(value);
+ setEnvironment(env);
+ }
+ return;
+ }
+ env.append(fname.append(value));
+ setEnvironment(env);
+}
+
+void KProcess::unsetEnv(const QString &name)
+{
+ QStringList env = environment();
+ if (env.isEmpty()) {
+ env = systemEnvironment();
+ env.removeAll(QString::fromLatin1(DUMMYENV));
+ }
+ QString fname(name);
+ fname.append(QLatin1Char('='));
+ for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
+ if ((*it).startsWith(fname)) {
+ env.erase(it);
+ if (env.isEmpty())
+ env.append(QString::fromLatin1(DUMMYENV));
+ setEnvironment(env);
+ return;
+ }
+}
+
+void KProcess::setProgram(const QString &exe, const QStringList &args)
+{
+ Q_D(KProcess);
+
+ d->prog = exe;
+ d->args = args;
+#ifdef Q_OS_WIN
+ setNativeArguments(QString());
+#endif
+}
+
+void KProcess::setProgram(const QStringList &argv)
+{
+ Q_D(KProcess);
+
+ Q_ASSERT( !argv.isEmpty() );
+ d->args = argv;
+ d->prog = d->args.takeFirst();
+#ifdef Q_OS_WIN
+ setNativeArguments(QString());
+#endif
+}
+
+KProcess &KProcess::operator<<(const QString &arg)
+{
+ Q_D(KProcess);
+
+ if (d->prog.isEmpty())
+ d->prog = arg;
+ else
+ d->args << arg;
+ return *this;
+}
+
+KProcess &KProcess::operator<<(const QStringList &args)
+{
+ Q_D(KProcess);
+
+ if (d->prog.isEmpty())
+ setProgram(args);
+ else
+ d->args << args;
+ return *this;
+}
+
+void KProcess::clearProgram()
+{
+ Q_D(KProcess);
+
+ d->prog.clear();
+ d->args.clear();
+#ifdef Q_OS_WIN
+ setNativeArguments(QString());
+#endif
+}
+
+/*void KProcess::setShellCommand(const QString &cmd)
+{
+ Q_D(KProcess);
+
+ KShell::Errors err;
+ d->args = KShell::splitArgs(
+ cmd, KShell::AbortOnMeta | KShell::TildeExpand, &err);
+ if (err == KShell::NoError && !d->args.isEmpty()) {
+ d->prog = KStandardDirs::findExe(d->args[0]);
+ if (!d->prog.isEmpty()) {
+ d->args.removeFirst();
+#ifdef Q_OS_WIN
+ setNativeArguments(QString());
+#endif
+ return;
+ }
+ }
+
+ d->args.clear();
+
+#ifdef Q_OS_UNIX
+// #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
+# if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__)
+ // If /bin/sh is a symlink, we can be pretty sure that it points to a
+ // POSIX shell - the original bourne shell is about the only non-POSIX
+ // shell still in use and it is always installed natively as /bin/sh.
+ d->prog = QFile::symLinkTarget(QString::fromLatin1("/bin/sh"));
+ if (d->prog.isEmpty()) {
+ // Try some known POSIX shells.
+ d->prog = KStandardDirs::findExe(QString::fromLatin1("ksh"));
+ if (d->prog.isEmpty()) {
+ d->prog = KStandardDirs::findExe(QString::fromLatin1("ash"));
+ if (d->prog.isEmpty()) {
+ d->prog = KStandardDirs::findExe(QString::fromLatin1("bash"));
+ if (d->prog.isEmpty()) {
+ d->prog = KStandardDirs::findExe(QString::fromLatin1("zsh"));
+ if (d->prog.isEmpty())
+ // We're pretty much screwed, to be honest ...
+ d->prog = QString::fromLatin1("/bin/sh");
+ }
+ }
+ }
+ }
+# else
+ d->prog = QString::fromLatin1("/bin/sh");
+# endif
+
+ d->args << QString::fromLatin1("-c") << cmd;
+#else // Q_OS_UNIX
+ // KMacroExpander::expandMacrosShellQuote(), KShell::quoteArg() and
+ // KShell::joinArgs() may generate these for security reasons.
+ setEnv(PERCENT_VARIABLE, QLatin1String("%"));
+
+#ifndef _WIN32_WCE
+ WCHAR sysdir[MAX_PATH + 1];
+ UINT size = GetSystemDirectoryW(sysdir, MAX_PATH + 1);
+ d->prog = QString::fromUtf16((const ushort *) sysdir, size);
+ d->prog += QLatin1String("\\cmd.exe");
+ setNativeArguments(QLatin1String("/V:OFF /S /C \"") + cmd + QLatin1Char('"'));
+#else
+ d->prog = QLatin1String("\\windows\\cmd.exe");
+ setNativeArguments(QLatin1String("/S /C \"") + cmd + QLatin1Char('"'));
+#endif
+#endif
+}*/
+
+QStringList KProcess::program() const
+{
+ Q_D(const KProcess);
+
+ QStringList argv = d->args;
+ argv.prepend(d->prog);
+ return argv;
+}
+
+void KProcess::start()
+{
+ Q_D(KProcess);
+
+ QProcess::start(d->prog, d->args, d->openMode);
+}
+
+int KProcess::execute(int msecs)
+{
+ start();
+ if (!waitForFinished(msecs)) {
+ kill();
+ waitForFinished(-1);
+ return -2;
+ }
+ return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1;
+}
+
+// static
+int KProcess::execute(const QString &exe, const QStringList &args, int msecs)
+{
+ KProcess p;
+ p.setProgram(exe, args);
+ return p.execute(msecs);
+}
+
+// static
+int KProcess::execute(const QStringList &argv, int msecs)
+{
+ KProcess p;
+ p.setProgram(argv);
+ return p.execute(msecs);
+}
+
+int KProcess::startDetached()
+{
+ Q_D(KProcess);
+
+ qint64 pid;
+ if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid))
+ return 0;
+ return (int) pid;
+}
+
+// static
+int KProcess::startDetached(const QString &exe, const QStringList &args)
+{
+ qint64 pid;
+ if (!QProcess::startDetached(exe, args, QString(), &pid))
+ return 0;
+ return (int) pid;
+}
+
+// static
+int KProcess::startDetached(const QStringList &argv)
+{
+ QStringList args = argv;
+ QString prog = args.takeFirst();
+ return startDetached(prog, args);
+}
+
+int KProcess::pid() const
+{
+#ifdef Q_OS_UNIX
+ return (int) QProcess::pid();
+#else
+ return QProcess::pid() ? QProcess::pid()->dwProcessId : 0;
+#endif
+}
+
+#include "moc_kprocess.cpp"
diff --git a/kgpg/kprocess.h b/kgpg/kprocess.h
new file mode 100644
index 0000000..6f28e24
--- /dev/null
+++ b/kgpg/kprocess.h
@@ -0,0 +1,341 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (C) 2007 Oswald Buddenhagen <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KPROCESS_H
+#define KPROCESS_H
+
+//#include <kdecore_export.h>
+
+#include <QtCore/QProcess>
+
+class KProcessPrivate;
+//#include "kprocess_p.h"
+/**
+ * \class KProcess kprocess.h <KProcess>
+ *
+ * Child process invocation, monitoring and control.
+ *
+ * This class extends QProcess by some useful functionality, overrides
+ * some defaults with saner values and wraps parts of the API into a more
+ * accessible one.
+ * This is the preferred way of spawning child processes in KDE; don't
+ * use QProcess directly.
+ *
+ * @author Oswald Buddenhagen <[email protected]>
+ **/
+class KProcess : public QProcess
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(KProcess)
+
+public:
+
+ /**
+ * Modes in which the output channels can be opened.
+ */
+ enum OutputChannelMode {
+ SeparateChannels = QProcess::SeparateChannels,
+ /**< Standard output and standard error are handled by KProcess
+ as separate channels */
+ MergedChannels = QProcess::MergedChannels,
+ /**< Standard output and standard error are handled by KProcess
+ as one channel */
+ ForwardedChannels = QProcess::ForwardedChannels,
+ /**< Both standard output and standard error are forwarded
+ to the parent process' respective channel */
+ OnlyStdoutChannel,
+ /**< Only standard output is handled; standard error is forwarded */
+ OnlyStderrChannel /**< Only standard error is handled; standard output is forwarded */
+ };
+
+ /**
+ * Constructor
+ */
+ explicit KProcess(QObject *parent = 0);
+
+ /**
+ * Destructor
+ */
+ virtual ~KProcess();
+
+ /**
+ * Set how to handle the output channels of the child process.
+ *
+ * The default is ForwardedChannels, which is unlike in QProcess.
+ * Do not request more than you actually handle, as this output is
+ * simply lost otherwise.
+ *
+ * This function must be called before starting the process.
+ *
+ * @param mode the output channel handling mode
+ */
+ void setOutputChannelMode(OutputChannelMode mode);
+
+ /**
+ * Query how the output channels of the child process are handled.
+ *
+ * @return the output channel handling mode
+ */
+ OutputChannelMode outputChannelMode() const;
+
+ /**
+ * Set the QIODevice open mode the process will be opened in.
+ *
+ * This function must be called before starting the process, obviously.
+ *
+ * @param mode the open mode. Note that this mode is automatically
+ * "reduced" according to the channel modes and redirections.
+ * The default is QIODevice::ReadWrite.
+ */
+ void setNextOpenMode(QIODevice::OpenMode mode);
+
+ /**
+ * Adds the variable @p name to the process' environment.
+ *
+ * This function must be called before starting the process.
+ *
+ * @param name the name of the environment variable
+ * @param value the new value for the environment variable
+ * @param overwrite if @c false and the environment variable is already
+ * set, the old value will be preserved
+ */
+ void setEnv(const QString &name, const QString &value, bool overwrite = true);
+
+ /**
+ * Removes the variable @p name from the process' environment.
+ *
+ * This function must be called before starting the process.
+ *
+ * @param name the name of the environment variable
+ */
+ void unsetEnv(const QString &name);
+
+ /**
+ * Empties the process' environment.
+ *
+ * Note that LD_LIBRARY_PATH/DYLD_LIBRARY_PATH is automatically added
+ * on *NIX.
+ *
+ * This function must be called before starting the process.
+ */
+ void clearEnvironment();
+
+ /**
+ * Set the program and the command line arguments.
+ *
+ * This function must be called before starting the process, obviously.
+ *
+ * @param exe the program to execute
+ * @param args the command line arguments for the program,
+ * one per list element
+ */
+ void setProgram(const QString &exe, const QStringList &args = QStringList());
+
+ /**
+ * @overload
+ *
+ * @param argv the program to execute and the command line arguments
+ * for the program, one per list element
+ */
+ void setProgram(const QStringList &argv);
+
+ /**
+ * Append an element to the command line argument list for this process.
+ *
+ * If no executable is set yet, it will be set instead.
+ *
+ * For example, doing an "ls -l /usr/local/bin" can be achieved by:
+ * \code
+ * KProcess p;
+ * p << "ls" << "-l" << "/usr/local/bin";
+ * ...
+ * \endcode
+ *
+ * This function must be called before starting the process, obviously.
+ *
+ * @param arg the argument to add
+ * @return a reference to this KProcess
+ */
+ KProcess &operator<<(const QString& arg);
+
+ /**
+ * @overload
+ *
+ * @param args the arguments to add
+ * @return a reference to this KProcess
+ */
+ KProcess &operator<<(const QStringList& args);
+
+ /**
+ * Clear the program and command line argument list.
+ */
+ void clearProgram();
+
+ /**
+ * Set a command to execute through a shell (a POSIX sh on *NIX
+ * and cmd.exe on Windows).
+ *
+ * Using this for anything but user-supplied commands is usually a bad
+ * idea, as the command's syntax depends on the platform.
+ * Redirections including pipes, etc. are better handled by the
+ * respective functions provided by QProcess.
+ *
+ * If KProcess determines that the command does not really need a
+ * shell, it will trasparently execute it without one for performance
+ * reasons.
+ *
+ * This function must be called before starting the process, obviously.
+ *
+ * @param cmd the command to execute through a shell.
+ * The caller must make sure that all filenames etc. are properly
+ * quoted when passed as argument. Failure to do so often results in
+ * serious security holes. See KShell::quoteArg().
+ */
+ void setShellCommand(const QString &cmd);
+
+ /**
+ * Obtain the currently set program and arguments.
+ *
+ * @return a list, the first element being the program, the remaining ones
+ * being command line arguments to the program.
+ */
+ QStringList program() const;
+
+ /**
+ * Start the process.
+ *
+ * @see QProcess::start(const QString &, const QStringList &, OpenMode)
+ */
+ void start();
+
+ /**
+ * Start the process, wait for it to finish, and return the exit code.
+ *
+ * This method is roughly equivalent to the sequence:
+ * <code>
+ * start();
+ * waitForFinished(msecs);
+ * return exitCode();
+ * </code>
+ *
+ * Unlike the other execute() variants this method is not static,
+ * so the process can be parametrized properly and talked to.
+ *
+ * @param msecs time to wait for process to exit before killing it
+ * @return -2 if the process could not be started, -1 if it crashed,
+ * otherwise its exit code
+ */
+ int execute(int msecs = -1);
+
+ /**
+ * @overload
+ *
+ * @param exe the program to execute
+ * @param args the command line arguments for the program,
+ * one per list element
+ * @param msecs time to wait for process to exit before killing it
+ * @return -2 if the process could not be started, -1 if it crashed,
+ * otherwise its exit code
+ */
+ static int execute(const QString &exe, const QStringList &args = QStringList(), int msecs = -1);
+
+ /**
+ * @overload
+ *
+ * @param argv the program to execute and the command line arguments
+ * for the program, one per list element
+ * @param msecs time to wait for process to exit before killing it
+ * @return -2 if the process could not be started, -1 if it crashed,
+ * otherwise its exit code
+ */
+ static int execute(const QStringList &argv, int msecs = -1);
+
+ /**
+ * Start the process and detach from it. See QProcess::startDetached()
+ * for details.
+ *
+ * Unlike the other startDetached() variants this method is not static,
+ * so the process can be parametrized properly.
+ * @note Currently, only the setProgram()/setShellCommand() and
+ * setWorkingDirectory() parametrizations are supported.
+ *
+ * The KProcess object may be re-used immediately after calling this
+ * function.
+ *
+ * @return the PID of the started process or 0 on error
+ */
+ int startDetached();
+
+ /**
+ * @overload
+ *
+ * @param exe the program to start
+ * @param args the command line arguments for the program,
+ * one per list element
+ * @return the PID of the started process or 0 on error
+ */
+ static int startDetached(const QString &exe, const QStringList &args = QStringList());
+
+ /**
+ * @overload
+ *
+ * @param argv the program to start and the command line arguments
+ * for the program, one per list element
+ * @return the PID of the started process or 0 on error
+ */
+ static int startDetached(const QStringList &argv);
+
+ /**
+ * Obtain the process' ID as known to the system.
+ *
+ * Unlike with QProcess::pid(), this is a real PID also on Windows.
+ *
+ * This function can be called only while the process is running.
+ * It cannot be applied to detached processes.
+ *
+ * @return the process ID
+ */
+ int pid() const;
+
+protected:
+ /**
+ * @internal
+ */
+ KProcess(KProcessPrivate *d, QObject *parent);
+
+ /**
+ * @internal
+ */
+ KProcessPrivate * const d_ptr;
+
+private:
+ // hide those
+ using QProcess::setReadChannelMode;
+ using QProcess::readChannelMode;
+ using QProcess::setProcessChannelMode;
+ using QProcess::processChannelMode;
+
+ Q_PRIVATE_SLOT(d_func(), void _k_forwardStdout())
+ Q_PRIVATE_SLOT(d_func(), void _k_forwardStderr())
+};
+
+#endif
+
diff --git a/kgpg/kprocess_p.h b/kgpg/kprocess_p.h
new file mode 100644
index 0000000..11d3356
--- /dev/null
+++ b/kgpg/kprocess_p.h
@@ -0,0 +1,50 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (C) 2007 Oswald Buddenhagen <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KPROCESS_P_H
+#define KPROCESS_P_H
+
+#include "kprocess.h"
+
+//class KProcess;
+
+class KProcessPrivate {
+ Q_DECLARE_PUBLIC(KProcess)
+protected:
+ KProcessPrivate() :
+ openMode(QIODevice::ReadWrite)
+ {
+ }
+ void writeAll(const QByteArray &buf, int fd);
+ void forwardStd(KProcess::ProcessChannel good, int fd);
+ void _k_forwardStdout();
+ void _k_forwardStderr();
+
+ QString prog;
+ QStringList args;
+ KProcess::OutputChannelMode outputChannelMode;
+ QIODevice::OpenMode openMode;
+
+ KProcess *q_ptr;
+};
+
+
+#endif