mirror of
https://github.com/QuasarApp/qca.git
synced 2025-04-29 04:54:31 +00:00
qca-gnupg: more refactoring
This commit is contained in:
parent
9b8f978bff
commit
6ee6f7f22a
@ -4,11 +4,10 @@ enable_plugin("gnupg")
|
||||
|
||||
set(QCA_GNUPG_MOC_SOURCES
|
||||
qca-gnupg.cpp
|
||||
gpgop.cpp
|
||||
gpgproc/gpgproc.cpp
|
||||
)
|
||||
|
||||
set(QCA_GNUPG_NONMOC_SOURCES
|
||||
gpgop.cpp
|
||||
utils.cpp
|
||||
gpgproc/sprocess.cpp
|
||||
mypgpkeycontext.cpp
|
||||
@ -19,12 +18,15 @@ set(QCA_GNUPG_NONMOC_SOURCES
|
||||
ringwatch.cpp
|
||||
lineconverter.cpp
|
||||
gpgaction.cpp
|
||||
gpgproc/gpgproc.cpp
|
||||
)
|
||||
|
||||
my_automoc(QCA_GNUPG_MOC_SOURCES)
|
||||
|
||||
qt4_wrap_cpp(EXTRA_GNUPG_SOURCES gpgop.h)
|
||||
qt4_wrap_cpp(EXTRA_GNUPG_SOURCES gpgop_p.h)
|
||||
qt4_wrap_cpp(EXTRA_GNUPG_SOURCES gpgproc/gpgproc.h)
|
||||
qt4_wrap_cpp(EXTRA_GNUPG_SOURCES gpgproc/gpgproc_p.h)
|
||||
qt4_wrap_cpp(EXTRA_GNUPG_SOURCES gpgproc/sprocess.h)
|
||||
qt4_wrap_cpp(EXTRA_GNUPG_SOURCES ringwatch.h)
|
||||
qt4_wrap_cpp(EXTRA_GNUPG_SOURCES mykeystorelist.h)
|
||||
|
@ -17,6 +17,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gpgop_p.h"
|
||||
#include "gpgop.h"
|
||||
#include "gpgaction.h"
|
||||
|
||||
@ -25,226 +26,197 @@ namespace gpgQCAPlugin {
|
||||
//----------------------------------------------------------------------------
|
||||
// GpgOp
|
||||
//----------------------------------------------------------------------------
|
||||
enum ResetMode
|
||||
GpgOp::Private::Private(GpgOp *_q)
|
||||
: QObject(_q)
|
||||
, sync(_q)
|
||||
, q(_q)
|
||||
, act(0)
|
||||
, waiting(false)
|
||||
{
|
||||
ResetSession = 0,
|
||||
ResetSessionAndData = 1,
|
||||
ResetAll = 2
|
||||
};
|
||||
reset(ResetAll);
|
||||
}
|
||||
|
||||
class GpgOp::Private : public QObject
|
||||
GpgOp::Private::~Private()
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QCA::Synchronizer sync;
|
||||
GpgOp *q;
|
||||
GpgAction *act;
|
||||
QString bin;
|
||||
GpgOp::Type op;
|
||||
GpgAction::Output output;
|
||||
QByteArray result;
|
||||
QString diagnosticText;
|
||||
QList<GpgOp::Event> eventList;
|
||||
bool waiting;
|
||||
reset(ResetAll);
|
||||
}
|
||||
|
||||
bool opt_ascii, opt_noagent, opt_alwaystrust;
|
||||
QString opt_pubfile, opt_secfile;
|
||||
|
||||
#ifdef GPG_PROFILE
|
||||
QTime timer;
|
||||
#endif
|
||||
|
||||
Private(GpgOp *_q) : QObject(_q), sync(_q), q(_q)
|
||||
void GpgOp::Private::reset(ResetMode mode)
|
||||
{
|
||||
if(act)
|
||||
{
|
||||
act->disconnect(this);
|
||||
act->setParent(0);
|
||||
act->deleteLater();
|
||||
|
||||
act = 0;
|
||||
waiting = false;
|
||||
|
||||
reset(ResetAll);
|
||||
}
|
||||
|
||||
~Private()
|
||||
if(mode >= ResetSessionAndData)
|
||||
{
|
||||
reset(ResetAll);
|
||||
output = GpgAction::Output();
|
||||
result.clear();
|
||||
diagnosticText = QString();
|
||||
eventList.clear();
|
||||
}
|
||||
|
||||
void reset(ResetMode mode)
|
||||
if(mode >= ResetAll)
|
||||
{
|
||||
if(act)
|
||||
{
|
||||
act->disconnect(this);
|
||||
act->setParent(0);
|
||||
act->deleteLater();
|
||||
|
||||
act = 0;
|
||||
}
|
||||
|
||||
if(mode >= ResetSessionAndData)
|
||||
{
|
||||
output = GpgAction::Output();
|
||||
result.clear();
|
||||
diagnosticText = QString();
|
||||
eventList.clear();
|
||||
}
|
||||
|
||||
if(mode >= ResetAll)
|
||||
{
|
||||
opt_ascii = false;
|
||||
opt_noagent = false;
|
||||
opt_alwaystrust = false;
|
||||
opt_pubfile = QString();
|
||||
opt_secfile = QString();
|
||||
}
|
||||
opt_ascii = false;
|
||||
opt_noagent = false;
|
||||
opt_alwaystrust = false;
|
||||
opt_pubfile = QString();
|
||||
opt_secfile = QString();
|
||||
}
|
||||
}
|
||||
|
||||
void make_act(GpgOp::Type _op)
|
||||
{
|
||||
reset(ResetSessionAndData);
|
||||
void GpgOp::Private::make_act(GpgOp::Type _op)
|
||||
{
|
||||
reset(ResetSessionAndData);
|
||||
|
||||
op = _op;
|
||||
op = _op;
|
||||
|
||||
act = new GpgAction(this);
|
||||
act = new GpgAction(this);
|
||||
|
||||
connect(act, SIGNAL(readyRead()), SLOT(act_readyRead()));
|
||||
connect(act, SIGNAL(bytesWritten(int)), SLOT(act_bytesWritten(int)));
|
||||
connect(act, SIGNAL(needPassphrase(const QString &)), SLOT(act_needPassphrase(const QString &)));
|
||||
connect(act, SIGNAL(needCard()), SLOT(act_needCard()));
|
||||
connect(act, SIGNAL(finished()), SLOT(act_finished()));
|
||||
connect(act, SIGNAL(readyReadDiagnosticText()), SLOT(act_readyReadDiagnosticText()));
|
||||
connect(act, SIGNAL(readyRead()), SLOT(act_readyRead()));
|
||||
connect(act, SIGNAL(bytesWritten(int)), SLOT(act_bytesWritten(int)));
|
||||
connect(act, SIGNAL(needPassphrase(const QString &)), SLOT(act_needPassphrase(const QString &)));
|
||||
connect(act, SIGNAL(needCard()), SLOT(act_needCard()));
|
||||
connect(act, SIGNAL(finished()), SLOT(act_finished()));
|
||||
connect(act, SIGNAL(readyReadDiagnosticText()), SLOT(act_readyReadDiagnosticText()));
|
||||
|
||||
act->input.bin = bin;
|
||||
act->input.op = op;
|
||||
act->input.opt_ascii = opt_ascii;
|
||||
act->input.opt_noagent = opt_noagent;
|
||||
act->input.opt_alwaystrust = opt_alwaystrust;
|
||||
act->input.opt_pubfile = opt_pubfile;
|
||||
act->input.opt_secfile = opt_secfile;
|
||||
}
|
||||
act->input.bin = bin;
|
||||
act->input.op = op;
|
||||
act->input.opt_ascii = opt_ascii;
|
||||
act->input.opt_noagent = opt_noagent;
|
||||
act->input.opt_alwaystrust = opt_alwaystrust;
|
||||
act->input.opt_pubfile = opt_pubfile;
|
||||
act->input.opt_secfile = opt_secfile;
|
||||
}
|
||||
|
||||
void eventReady(const GpgOp::Event &e)
|
||||
{
|
||||
eventList += e;
|
||||
sync.conditionMet();
|
||||
}
|
||||
void GpgOp::Private::eventReady(const GpgOp::Event &e)
|
||||
{
|
||||
eventList += e;
|
||||
sync.conditionMet();
|
||||
}
|
||||
|
||||
void eventReady(GpgOp::Event::Type type)
|
||||
{
|
||||
GpgOp::Event e;
|
||||
e.type = type;
|
||||
eventReady(e);
|
||||
}
|
||||
void GpgOp::Private::eventReady(GpgOp::Event::Type type)
|
||||
{
|
||||
GpgOp::Event e;
|
||||
e.type = type;
|
||||
eventReady(e);
|
||||
}
|
||||
|
||||
void eventReady(GpgOp::Event::Type type, int written)
|
||||
{
|
||||
GpgOp::Event e;
|
||||
e.type = type;
|
||||
e.written = written;
|
||||
eventReady(e);
|
||||
}
|
||||
void GpgOp::Private::eventReady(GpgOp::Event::Type type, int written)
|
||||
{
|
||||
GpgOp::Event e;
|
||||
e.type = type;
|
||||
e.written = written;
|
||||
eventReady(e);
|
||||
}
|
||||
|
||||
void eventReady(GpgOp::Event::Type type, const QString &keyId)
|
||||
{
|
||||
GpgOp::Event e;
|
||||
e.type = type;
|
||||
e.keyId = keyId;
|
||||
eventReady(e);
|
||||
}
|
||||
void GpgOp::Private::eventReady(GpgOp::Event::Type type, const QString &keyId)
|
||||
{
|
||||
GpgOp::Event e;
|
||||
e.type = type;
|
||||
e.keyId = keyId;
|
||||
eventReady(e);
|
||||
}
|
||||
|
||||
public slots:
|
||||
void act_readyRead()
|
||||
{
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::ReadyRead);
|
||||
else
|
||||
emit q->readyRead();
|
||||
}
|
||||
void GpgOp::Private::act_readyRead()
|
||||
{
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::ReadyRead);
|
||||
else
|
||||
emit q->readyRead();
|
||||
}
|
||||
|
||||
void act_bytesWritten(int bytes)
|
||||
{
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::BytesWritten, bytes);
|
||||
else
|
||||
emit q->bytesWritten(bytes);
|
||||
}
|
||||
void GpgOp::Private::act_bytesWritten(int bytes)
|
||||
{
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::BytesWritten, bytes);
|
||||
else
|
||||
emit q->bytesWritten(bytes);
|
||||
}
|
||||
|
||||
void act_needPassphrase(const QString &keyId)
|
||||
{
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::NeedPassphrase, keyId);
|
||||
else
|
||||
emit q->needPassphrase(keyId);
|
||||
}
|
||||
void GpgOp::Private::act_needPassphrase(const QString &keyId)
|
||||
{
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::NeedPassphrase, keyId);
|
||||
else
|
||||
emit q->needPassphrase(keyId);
|
||||
}
|
||||
|
||||
void act_needCard()
|
||||
{
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::NeedCard);
|
||||
else
|
||||
emit q->needCard();
|
||||
}
|
||||
void GpgOp::Private::act_needCard()
|
||||
{
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::NeedCard);
|
||||
else
|
||||
emit q->needCard();
|
||||
}
|
||||
|
||||
void act_readyReadDiagnosticText()
|
||||
{
|
||||
QString s = act->readDiagnosticText();
|
||||
//printf("dtext ready: [%s]\n", qPrintable(s));
|
||||
diagnosticText += s;
|
||||
void GpgOp::Private::act_readyReadDiagnosticText()
|
||||
{
|
||||
QString s = act->readDiagnosticText();
|
||||
//printf("dtext ready: [%s]\n", qPrintable(s));
|
||||
diagnosticText += s;
|
||||
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::ReadyReadDiagnosticText);
|
||||
else
|
||||
emit q->readyReadDiagnosticText();
|
||||
}
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::ReadyReadDiagnosticText);
|
||||
else
|
||||
emit q->readyReadDiagnosticText();
|
||||
}
|
||||
|
||||
void act_finished()
|
||||
{
|
||||
void GpgOp::Private::act_finished()
|
||||
{
|
||||
#ifdef GPG_PROFILE
|
||||
if(op == GpgOp::Encrypt)
|
||||
printf("<< doEncrypt: %d >>\n", timer.elapsed());
|
||||
if(op == GpgOp::Encrypt)
|
||||
printf("<< doEncrypt: %d >>\n", timer.elapsed());
|
||||
#endif
|
||||
|
||||
result = act->read();
|
||||
diagnosticText += act->readDiagnosticText();
|
||||
output = act->output;
|
||||
result = act->read();
|
||||
diagnosticText += act->readDiagnosticText();
|
||||
output = act->output;
|
||||
|
||||
QMap<int, QString> errmap;
|
||||
errmap[GpgOp::ErrorProcess] = "ErrorProcess";
|
||||
errmap[GpgOp::ErrorPassphrase] = "ErrorPassphrase";
|
||||
errmap[GpgOp::ErrorFormat] = "ErrorFormat";
|
||||
errmap[GpgOp::ErrorSignerExpired] = "ErrorSignerExpired";
|
||||
errmap[GpgOp::ErrorEncryptExpired] = "ErrorEncryptExpired";
|
||||
errmap[GpgOp::ErrorEncryptUntrusted] = "ErrorEncryptUntrusted";
|
||||
errmap[GpgOp::ErrorEncryptInvalid] = "ErrorEncryptInvalid";
|
||||
errmap[GpgOp::ErrorDecryptNoKey] = "ErrorDecryptNoKey";
|
||||
errmap[GpgOp::ErrorUnknown] = "ErrorUnknown";
|
||||
if(output.success)
|
||||
diagnosticText += "GpgAction success\n";
|
||||
QMap<int, QString> errmap;
|
||||
errmap[GpgOp::ErrorProcess] = "ErrorProcess";
|
||||
errmap[GpgOp::ErrorPassphrase] = "ErrorPassphrase";
|
||||
errmap[GpgOp::ErrorFormat] = "ErrorFormat";
|
||||
errmap[GpgOp::ErrorSignerExpired] = "ErrorSignerExpired";
|
||||
errmap[GpgOp::ErrorEncryptExpired] = "ErrorEncryptExpired";
|
||||
errmap[GpgOp::ErrorEncryptUntrusted] = "ErrorEncryptUntrusted";
|
||||
errmap[GpgOp::ErrorEncryptInvalid] = "ErrorEncryptInvalid";
|
||||
errmap[GpgOp::ErrorDecryptNoKey] = "ErrorDecryptNoKey";
|
||||
errmap[GpgOp::ErrorUnknown] = "ErrorUnknown";
|
||||
if(output.success)
|
||||
diagnosticText += "GpgAction success\n";
|
||||
else
|
||||
diagnosticText += QString("GpgAction error: %1\n").arg(errmap[output.errorCode]);
|
||||
|
||||
if(output.wasSigned)
|
||||
{
|
||||
QString s;
|
||||
if(output.verifyResult == GpgOp::VerifyGood)
|
||||
s = "VerifyGood";
|
||||
else if(output.verifyResult == GpgOp::VerifyBad)
|
||||
s = "VerifyBad";
|
||||
else
|
||||
diagnosticText += QString("GpgAction error: %1\n").arg(errmap[output.errorCode]);
|
||||
|
||||
if(output.wasSigned)
|
||||
{
|
||||
QString s;
|
||||
if(output.verifyResult == GpgOp::VerifyGood)
|
||||
s = "VerifyGood";
|
||||
else if(output.verifyResult == GpgOp::VerifyBad)
|
||||
s = "VerifyBad";
|
||||
else
|
||||
s = "VerifyNoKey";
|
||||
diagnosticText += QString("wasSigned: verifyResult: %1\n").arg(s);
|
||||
}
|
||||
|
||||
//printf("diagnosticText:\n%s", qPrintable(diagnosticText));
|
||||
|
||||
reset(ResetSession);
|
||||
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::Finished);
|
||||
else
|
||||
emit q->finished();
|
||||
s = "VerifyNoKey";
|
||||
diagnosticText += QString("wasSigned: verifyResult: %1\n").arg(s);
|
||||
}
|
||||
};
|
||||
|
||||
//printf("diagnosticText:\n%s", qPrintable(diagnosticText));
|
||||
|
||||
reset(ResetSession);
|
||||
|
||||
if(waiting)
|
||||
eventReady(GpgOp::Event::Finished);
|
||||
else
|
||||
emit q->finished();
|
||||
}
|
||||
|
||||
GpgOp::GpgOp(const QString &bin, QObject *parent)
|
||||
:QObject(parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private(this);
|
||||
d->bin = bin;
|
||||
@ -510,5 +482,3 @@ GpgOp::VerifyResult GpgOp::verifyResult() const
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "gpgop.moc"
|
||||
|
75
plugins/qca-gnupg/gpgop_p.h
Normal file
75
plugins/qca-gnupg/gpgop_p.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2005 Justin Karneges <justin@affinix.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpgop.h"
|
||||
#include "gpgaction.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace gpgQCAPlugin {
|
||||
|
||||
enum ResetMode
|
||||
{
|
||||
ResetSession = 0,
|
||||
ResetSessionAndData = 1,
|
||||
ResetAll = 2
|
||||
};
|
||||
|
||||
class GpgOp::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QCA::Synchronizer sync;
|
||||
GpgOp *q;
|
||||
GpgAction *act;
|
||||
QString bin;
|
||||
GpgOp::Type op;
|
||||
GpgAction::Output output;
|
||||
QByteArray result;
|
||||
QString diagnosticText;
|
||||
QList<GpgOp::Event> eventList;
|
||||
bool waiting;
|
||||
|
||||
bool opt_ascii, opt_noagent, opt_alwaystrust;
|
||||
QString opt_pubfile, opt_secfile;
|
||||
|
||||
#ifdef GPG_PROFILE
|
||||
QTime timer;
|
||||
#endif
|
||||
|
||||
Private(GpgOp *_q);
|
||||
~Private();
|
||||
void reset(ResetMode mode);
|
||||
void make_act(GpgOp::Type _op);
|
||||
void eventReady(const GpgOp::Event &e);
|
||||
void eventReady(GpgOp::Event::Type type);
|
||||
void eventReady(GpgOp::Event::Type type, int written);
|
||||
void eventReady(GpgOp::Event::Type type, const QString &keyId);
|
||||
|
||||
public slots:
|
||||
void act_readyRead();
|
||||
void act_bytesWritten(int bytes);
|
||||
void act_needPassphrase(const QString &keyId);
|
||||
void act_needCard();
|
||||
void act_readyReadDiagnosticText();
|
||||
void act_finished();
|
||||
};
|
||||
|
||||
} // namespace gpgQCAPlugin
|
@ -17,15 +17,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gpgproc.h"
|
||||
|
||||
#include "sprocess.h"
|
||||
#include "gpgproc_p.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#define QT_PIPE_HACK
|
||||
#endif
|
||||
|
||||
#define QPROC_SIGNAL_RELAY
|
||||
|
||||
using namespace QCA;
|
||||
|
||||
@ -38,218 +35,126 @@ void releaseAndDeleteLater(QObject *owner, QObject *obj)
|
||||
obj->deleteLater();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// QProcessSignalRelay
|
||||
//----------------------------------------------------------------------------
|
||||
class QProcessSignalRelay : public QObject
|
||||
|
||||
GPGProc::Private::Private(GPGProc *_q)
|
||||
: QObject(_q)
|
||||
, q(_q)
|
||||
, pipeAux(this)
|
||||
, pipeCommand(this)
|
||||
, pipeStatus(this)
|
||||
, startTrigger(this)
|
||||
, doneTrigger(this)
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QProcessSignalRelay(QProcess *proc, QObject *parent = 0)
|
||||
:QObject(parent)
|
||||
{
|
||||
qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError");
|
||||
connect(proc, SIGNAL(started()), SLOT(proc_started()), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(readyReadStandardOutput()), SLOT(proc_readyReadStandardOutput()), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(readyReadStandardError()), SLOT(proc_readyReadStandardError()), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(bytesWritten(qint64)), SLOT(proc_bytesWritten(qint64)), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(finished(int)), SLOT(proc_finished(int)), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(error(QProcess::ProcessError)), SLOT(proc_error(QProcess::ProcessError)), Qt::QueuedConnection);
|
||||
}
|
||||
qRegisterMetaType<gpgQCAPlugin::GPGProc::Error>("gpgQCAPlugin::GPGProc::Error");
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void readyReadStandardOutput();
|
||||
void readyReadStandardError();
|
||||
void bytesWritten(qint64);
|
||||
void finished(int);
|
||||
void error(QProcess::ProcessError);
|
||||
|
||||
public slots:
|
||||
void proc_started()
|
||||
{
|
||||
emit started();
|
||||
}
|
||||
|
||||
void proc_readyReadStandardOutput()
|
||||
{
|
||||
emit readyReadStandardOutput();
|
||||
}
|
||||
|
||||
void proc_readyReadStandardError()
|
||||
{
|
||||
emit readyReadStandardError();
|
||||
}
|
||||
|
||||
void proc_bytesWritten(qint64 x)
|
||||
{
|
||||
emit bytesWritten(x);
|
||||
}
|
||||
|
||||
void proc_finished(int x)
|
||||
{
|
||||
emit finished(x);
|
||||
}
|
||||
|
||||
void proc_error(QProcess::ProcessError x)
|
||||
{
|
||||
emit error(x);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// GPGProc
|
||||
//----------------------------------------------------------------------------
|
||||
enum ResetMode
|
||||
{
|
||||
ResetSession = 0,
|
||||
ResetSessionAndData = 1,
|
||||
ResetAll = 2
|
||||
};
|
||||
|
||||
class GPGProc::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GPGProc *q;
|
||||
QString bin;
|
||||
QStringList args;
|
||||
GPGProc::Mode mode;
|
||||
SProcess *proc;
|
||||
proc = 0;
|
||||
#ifdef QPROC_SIGNAL_RELAY
|
||||
QProcessSignalRelay *proc_relay;
|
||||
proc_relay = 0;
|
||||
#endif
|
||||
QPipe pipeAux, pipeCommand, pipeStatus;
|
||||
QByteArray statusBuf;
|
||||
QStringList statusLines;
|
||||
GPGProc::Error error;
|
||||
int exitCode;
|
||||
SafeTimer startTrigger, doneTrigger;
|
||||
startTrigger.setSingleShot(true);
|
||||
doneTrigger.setSingleShot(true);
|
||||
|
||||
QByteArray pre_stdin, pre_aux;
|
||||
#ifdef QPIPE_SECURE
|
||||
SecureArray pre_command;
|
||||
#else
|
||||
QByteArray pre_command;
|
||||
#endif
|
||||
bool pre_stdin_close, pre_aux_close, pre_command_close;
|
||||
connect(&pipeAux.writeEnd(), SIGNAL(bytesWritten(int)), SLOT(aux_written(int)));
|
||||
connect(&pipeAux.writeEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(aux_error(QCA::QPipeEnd::Error)));
|
||||
connect(&pipeCommand.writeEnd(), SIGNAL(bytesWritten(int)), SLOT(command_written(int)));
|
||||
connect(&pipeCommand.writeEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(command_error(QCA::QPipeEnd::Error)));
|
||||
connect(&pipeStatus.readEnd(), SIGNAL(readyRead()), SLOT(status_read()));
|
||||
connect(&pipeStatus.readEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(status_error(QCA::QPipeEnd::Error)));
|
||||
connect(&startTrigger, SIGNAL(timeout()), SLOT(doStart()));
|
||||
connect(&doneTrigger, SIGNAL(timeout()), SLOT(doTryDone()));
|
||||
|
||||
bool need_status, fin_process, fin_process_success, fin_status;
|
||||
QByteArray leftover_stdout;
|
||||
QByteArray leftover_stderr;
|
||||
reset(ResetSessionAndData);
|
||||
}
|
||||
|
||||
Private(GPGProc *_q) : QObject(_q), q(_q), pipeAux(this), pipeCommand(this), pipeStatus(this), startTrigger(this), doneTrigger(this)
|
||||
{
|
||||
qRegisterMetaType<gpgQCAPlugin::GPGProc::Error>("gpgQCAPlugin::GPGProc::Error");
|
||||
GPGProc::Private::~Private()
|
||||
{
|
||||
reset(ResetSession);
|
||||
}
|
||||
|
||||
proc = 0;
|
||||
#ifdef QPROC_SIGNAL_RELAY
|
||||
proc_relay = 0;
|
||||
#endif
|
||||
startTrigger.setSingleShot(true);
|
||||
doneTrigger.setSingleShot(true);
|
||||
|
||||
connect(&pipeAux.writeEnd(), SIGNAL(bytesWritten(int)), SLOT(aux_written(int)));
|
||||
connect(&pipeAux.writeEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(aux_error(QCA::QPipeEnd::Error)));
|
||||
connect(&pipeCommand.writeEnd(), SIGNAL(bytesWritten(int)), SLOT(command_written(int)));
|
||||
connect(&pipeCommand.writeEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(command_error(QCA::QPipeEnd::Error)));
|
||||
connect(&pipeStatus.readEnd(), SIGNAL(readyRead()), SLOT(status_read()));
|
||||
connect(&pipeStatus.readEnd(), SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(status_error(QCA::QPipeEnd::Error)));
|
||||
connect(&startTrigger, SIGNAL(timeout()), SLOT(doStart()));
|
||||
connect(&doneTrigger, SIGNAL(timeout()), SLOT(doTryDone()));
|
||||
|
||||
reset(ResetSessionAndData);
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
reset(ResetSession);
|
||||
}
|
||||
|
||||
void closePipes()
|
||||
{
|
||||
void GPGProc::Private::closePipes()
|
||||
{
|
||||
#ifdef QT_PIPE_HACK
|
||||
pipeAux.readEnd().reset();
|
||||
pipeCommand.readEnd().reset();
|
||||
pipeStatus.writeEnd().reset();
|
||||
pipeAux.readEnd().reset();
|
||||
pipeCommand.readEnd().reset();
|
||||
pipeStatus.writeEnd().reset();
|
||||
#endif
|
||||
|
||||
pipeAux.reset();
|
||||
pipeCommand.reset();
|
||||
pipeStatus.reset();
|
||||
}
|
||||
pipeAux.reset();
|
||||
pipeCommand.reset();
|
||||
pipeStatus.reset();
|
||||
}
|
||||
|
||||
void reset(ResetMode mode)
|
||||
{
|
||||
void GPGProc::Private::reset(ResetMode mode)
|
||||
{
|
||||
#ifndef QT_PIPE_HACK
|
||||
closePipes();
|
||||
closePipes();
|
||||
#endif
|
||||
|
||||
if(proc)
|
||||
if(proc)
|
||||
{
|
||||
proc->disconnect(this);
|
||||
|
||||
if(proc->state() != QProcess::NotRunning)
|
||||
{
|
||||
proc->disconnect(this);
|
||||
// Before try to correct end proccess
|
||||
// Terminate if failed
|
||||
proc->close();
|
||||
bool finished = proc->waitForFinished(5000);
|
||||
if (!finished)
|
||||
proc->terminate();
|
||||
}
|
||||
|
||||
if(proc->state() != QProcess::NotRunning)
|
||||
{
|
||||
// Before try to correct end proccess
|
||||
// Terminate if failed
|
||||
proc->close();
|
||||
bool finished = proc->waitForFinished(5000);
|
||||
if (!finished)
|
||||
proc->terminate();
|
||||
}
|
||||
|
||||
proc->setParent(0);
|
||||
proc->setParent(0);
|
||||
#ifdef QPROC_SIGNAL_RELAY
|
||||
releaseAndDeleteLater(this, proc_relay);
|
||||
proc_relay = 0;
|
||||
delete proc; // should be safe to do thanks to relay
|
||||
releaseAndDeleteLater(this, proc_relay);
|
||||
proc_relay = 0;
|
||||
delete proc; // should be safe to do thanks to relay
|
||||
#else
|
||||
proc->deleteLater();
|
||||
proc->deleteLater();
|
||||
#endif
|
||||
proc = 0;
|
||||
}
|
||||
|
||||
#ifdef QT_PIPE_HACK
|
||||
closePipes();
|
||||
#endif
|
||||
|
||||
startTrigger.stop();
|
||||
doneTrigger.stop();
|
||||
|
||||
pre_stdin.clear();
|
||||
pre_aux.clear();
|
||||
pre_command.clear();
|
||||
pre_stdin_close = false;
|
||||
pre_aux_close = false;
|
||||
pre_command_close = false;
|
||||
|
||||
need_status = false;
|
||||
fin_process = false;
|
||||
fin_status = false;
|
||||
|
||||
if(mode >= ResetSessionAndData)
|
||||
{
|
||||
statusBuf.clear();
|
||||
statusLines.clear();
|
||||
leftover_stdout.clear();
|
||||
leftover_stderr.clear();
|
||||
error = GPGProc::FailedToStart;
|
||||
exitCode = -1;
|
||||
}
|
||||
proc = 0;
|
||||
}
|
||||
|
||||
bool setupPipes(bool makeAux)
|
||||
#ifdef QT_PIPE_HACK
|
||||
closePipes();
|
||||
#endif
|
||||
|
||||
startTrigger.stop();
|
||||
doneTrigger.stop();
|
||||
|
||||
pre_stdin.clear();
|
||||
pre_aux.clear();
|
||||
pre_command.clear();
|
||||
pre_stdin_close = false;
|
||||
pre_aux_close = false;
|
||||
pre_command_close = false;
|
||||
|
||||
need_status = false;
|
||||
fin_process = false;
|
||||
fin_status = false;
|
||||
|
||||
if(mode >= ResetSessionAndData)
|
||||
{
|
||||
if(makeAux && !pipeAux.create())
|
||||
{
|
||||
closePipes();
|
||||
emit q->debug("Error creating pipeAux");
|
||||
return false;
|
||||
}
|
||||
statusBuf.clear();
|
||||
statusLines.clear();
|
||||
leftover_stdout.clear();
|
||||
leftover_stderr.clear();
|
||||
error = GPGProc::FailedToStart;
|
||||
exitCode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool GPGProc::Private::setupPipes(bool makeAux)
|
||||
{
|
||||
if(makeAux && !pipeAux.create())
|
||||
{
|
||||
closePipes();
|
||||
emit q->debug("Error creating pipeAux");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef QPIPE_SECURE
|
||||
if(!pipeCommand.create(true)) // secure
|
||||
if(!pipeCommand.create(true)) // secure
|
||||
#else
|
||||
if(!pipeCommand.create())
|
||||
#endif
|
||||
@ -259,321 +164,318 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pipeStatus.create())
|
||||
{
|
||||
closePipes();
|
||||
emit q->debug("Error creating pipeStatus");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if(!pipeStatus.create())
|
||||
{
|
||||
closePipes();
|
||||
emit q->debug("Error creating pipeStatus");
|
||||
return false;
|
||||
}
|
||||
|
||||
void setupArguments()
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPGProc::Private::setupArguments()
|
||||
{
|
||||
QStringList fullargs;
|
||||
fullargs += "--no-tty";
|
||||
|
||||
if(mode == ExtendedMode)
|
||||
{
|
||||
QStringList fullargs;
|
||||
fullargs += "--no-tty";
|
||||
fullargs += "--enable-special-filenames";
|
||||
|
||||
if(mode == ExtendedMode)
|
||||
{
|
||||
fullargs += "--enable-special-filenames";
|
||||
fullargs += "--status-fd";
|
||||
fullargs += QString::number(pipeStatus.writeEnd().idAsInt());
|
||||
|
||||
fullargs += "--status-fd";
|
||||
fullargs += QString::number(pipeStatus.writeEnd().idAsInt());
|
||||
|
||||
fullargs += "--command-fd";
|
||||
fullargs += QString::number(pipeCommand.readEnd().idAsInt());
|
||||
}
|
||||
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
{
|
||||
QString a = args[n];
|
||||
if(mode == ExtendedMode && a == "-&?")
|
||||
fullargs += QString("-&") + QString::number(pipeAux.readEnd().idAsInt());
|
||||
else
|
||||
fullargs += a;
|
||||
}
|
||||
|
||||
QString fullcmd = fullargs.join(" ");
|
||||
emit q->debug(QString("Running: [") + bin + ' ' + fullcmd + ']');
|
||||
|
||||
args = fullargs;
|
||||
fullargs += "--command-fd";
|
||||
fullargs += QString::number(pipeCommand.readEnd().idAsInt());
|
||||
}
|
||||
|
||||
public slots:
|
||||
void doStart()
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
{
|
||||
QString a = args[n];
|
||||
if(mode == ExtendedMode && a == "-&?")
|
||||
fullargs += QString("-&") + QString::number(pipeAux.readEnd().idAsInt());
|
||||
else
|
||||
fullargs += a;
|
||||
}
|
||||
|
||||
QString fullcmd = fullargs.join(" ");
|
||||
emit q->debug(QString("Running: [") + bin + ' ' + fullcmd + ']');
|
||||
|
||||
args = fullargs;
|
||||
}
|
||||
|
||||
void GPGProc::Private::doStart()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
// Note: for unix, inheritability is set in SProcess
|
||||
if(pipeAux.readEnd().isValid())
|
||||
pipeAux.readEnd().setInheritable(true);
|
||||
if(pipeCommand.readEnd().isValid())
|
||||
pipeCommand.readEnd().setInheritable(true);
|
||||
if(pipeStatus.writeEnd().isValid())
|
||||
pipeStatus.writeEnd().setInheritable(true);
|
||||
// Note: for unix, inheritability is set in SProcess
|
||||
if(pipeAux.readEnd().isValid())
|
||||
pipeAux.readEnd().setInheritable(true);
|
||||
if(pipeCommand.readEnd().isValid())
|
||||
pipeCommand.readEnd().setInheritable(true);
|
||||
if(pipeStatus.writeEnd().isValid())
|
||||
pipeStatus.writeEnd().setInheritable(true);
|
||||
#endif
|
||||
|
||||
setupArguments();
|
||||
setupArguments();
|
||||
|
||||
proc->start(bin, args);
|
||||
proc->waitForStarted();
|
||||
proc->start(bin, args);
|
||||
proc->waitForStarted();
|
||||
|
||||
pipeAux.readEnd().close();
|
||||
pipeCommand.readEnd().close();
|
||||
pipeStatus.writeEnd().close();
|
||||
}
|
||||
pipeAux.readEnd().close();
|
||||
pipeCommand.readEnd().close();
|
||||
pipeStatus.writeEnd().close();
|
||||
}
|
||||
|
||||
void aux_written(int x)
|
||||
void GPGProc::Private::aux_written(int x)
|
||||
{
|
||||
emit q->bytesWrittenAux(x);
|
||||
}
|
||||
|
||||
void GPGProc::Private::aux_error(QCA::QPipeEnd::Error)
|
||||
{
|
||||
emit q->debug("Aux: Pipe error");
|
||||
reset(ResetSession);
|
||||
emit q->error(GPGProc::ErrorWrite);
|
||||
}
|
||||
|
||||
void GPGProc::Private::command_written(int x)
|
||||
{
|
||||
emit q->bytesWrittenCommand(x);
|
||||
}
|
||||
|
||||
void GPGProc::Private::command_error(QCA::QPipeEnd::Error)
|
||||
{
|
||||
emit q->debug("Command: Pipe error");
|
||||
reset(ResetSession);
|
||||
emit q->error(GPGProc::ErrorWrite);
|
||||
}
|
||||
|
||||
void GPGProc::Private::status_read()
|
||||
{
|
||||
if(readAndProcessStatusData())
|
||||
emit q->readyReadStatusLines();
|
||||
}
|
||||
|
||||
void GPGProc::Private::status_error(QCA::QPipeEnd::Error e)
|
||||
{
|
||||
if(e == QPipeEnd::ErrorEOF)
|
||||
emit q->debug("Status: Closed (EOF)");
|
||||
else
|
||||
emit q->debug("Status: Closed (gone)");
|
||||
|
||||
fin_status = true;
|
||||
doTryDone();
|
||||
}
|
||||
|
||||
void GPGProc::Private::proc_started()
|
||||
{
|
||||
emit q->debug("Process started");
|
||||
|
||||
// Note: we don't close these here anymore. instead we
|
||||
// do it just after calling proc->start().
|
||||
// close these, we don't need them
|
||||
/*pipeAux.readEnd().close();
|
||||
pipeCommand.readEnd().close();
|
||||
pipeStatus.writeEnd().close();*/
|
||||
|
||||
// do the pre* stuff
|
||||
if(!pre_stdin.isEmpty())
|
||||
{
|
||||
emit q->bytesWrittenAux(x);
|
||||
proc->write(pre_stdin);
|
||||
pre_stdin.clear();
|
||||
}
|
||||
|
||||
void aux_error(QCA::QPipeEnd::Error)
|
||||
if(!pre_aux.isEmpty())
|
||||
{
|
||||
emit q->debug("Aux: Pipe error");
|
||||
reset(ResetSession);
|
||||
emit q->error(GPGProc::ErrorWrite);
|
||||
pipeAux.writeEnd().write(pre_aux);
|
||||
pre_aux.clear();
|
||||
}
|
||||
|
||||
void command_written(int x)
|
||||
if(!pre_command.isEmpty())
|
||||
{
|
||||
emit q->bytesWrittenCommand(x);
|
||||
}
|
||||
|
||||
void command_error(QCA::QPipeEnd::Error)
|
||||
{
|
||||
emit q->debug("Command: Pipe error");
|
||||
reset(ResetSession);
|
||||
emit q->error(GPGProc::ErrorWrite);
|
||||
}
|
||||
|
||||
void status_read()
|
||||
{
|
||||
if(readAndProcessStatusData())
|
||||
emit q->readyReadStatusLines();
|
||||
}
|
||||
|
||||
void status_error(QCA::QPipeEnd::Error e)
|
||||
{
|
||||
if(e == QPipeEnd::ErrorEOF)
|
||||
emit q->debug("Status: Closed (EOF)");
|
||||
else
|
||||
emit q->debug("Status: Closed (gone)");
|
||||
|
||||
fin_status = true;
|
||||
doTryDone();
|
||||
}
|
||||
|
||||
void proc_started()
|
||||
{
|
||||
emit q->debug("Process started");
|
||||
|
||||
// Note: we don't close these here anymore. instead we
|
||||
// do it just after calling proc->start().
|
||||
// close these, we don't need them
|
||||
/*pipeAux.readEnd().close();
|
||||
pipeCommand.readEnd().close();
|
||||
pipeStatus.writeEnd().close();*/
|
||||
|
||||
// do the pre* stuff
|
||||
if(!pre_stdin.isEmpty())
|
||||
{
|
||||
proc->write(pre_stdin);
|
||||
pre_stdin.clear();
|
||||
}
|
||||
if(!pre_aux.isEmpty())
|
||||
{
|
||||
pipeAux.writeEnd().write(pre_aux);
|
||||
pre_aux.clear();
|
||||
}
|
||||
if(!pre_command.isEmpty())
|
||||
{
|
||||
#ifdef QPIPE_SECURE
|
||||
pipeCommand.writeEnd().writeSecure(pre_command);
|
||||
pipeCommand.writeEnd().writeSecure(pre_command);
|
||||
#else
|
||||
pipeCommand.writeEnd().write(pre_command);
|
||||
pipeCommand.writeEnd().write(pre_command);
|
||||
#endif
|
||||
pre_command.clear();
|
||||
}
|
||||
pre_command.clear();
|
||||
}
|
||||
|
||||
if(pre_stdin_close)
|
||||
if(pre_stdin_close)
|
||||
{
|
||||
proc->waitForBytesWritten();
|
||||
proc->closeWriteChannel();
|
||||
}
|
||||
|
||||
if(pre_aux_close)
|
||||
pipeAux.writeEnd().close();
|
||||
if(pre_command_close)
|
||||
pipeCommand.writeEnd().close();
|
||||
}
|
||||
|
||||
void GPGProc::Private::proc_readyReadStandardOutput()
|
||||
{
|
||||
emit q->readyReadStdout();
|
||||
}
|
||||
|
||||
void GPGProc::Private::proc_readyReadStandardError()
|
||||
{
|
||||
emit q->readyReadStderr();
|
||||
}
|
||||
|
||||
void GPGProc::Private::proc_bytesWritten(qint64 lx)
|
||||
{
|
||||
int x = (int)lx;
|
||||
emit q->bytesWrittenStdin(x);
|
||||
}
|
||||
|
||||
void GPGProc::Private::proc_finished(int x)
|
||||
{
|
||||
emit q->debug(QString("Process finished: %1").arg(x));
|
||||
exitCode = x;
|
||||
|
||||
fin_process = true;
|
||||
fin_process_success = true;
|
||||
|
||||
if(need_status && !fin_status)
|
||||
{
|
||||
pipeStatus.readEnd().finalize();
|
||||
fin_status = true;
|
||||
if(readAndProcessStatusData())
|
||||
{
|
||||
proc->waitForBytesWritten();
|
||||
proc->closeWriteChannel();
|
||||
doneTrigger.start();
|
||||
emit q->readyReadStatusLines();
|
||||
return;
|
||||
}
|
||||
|
||||
if(pre_aux_close)
|
||||
pipeAux.writeEnd().close();
|
||||
if(pre_command_close)
|
||||
pipeCommand.writeEnd().close();
|
||||
}
|
||||
|
||||
void proc_readyReadStandardOutput()
|
||||
{
|
||||
emit q->readyReadStdout();
|
||||
}
|
||||
doTryDone();
|
||||
}
|
||||
|
||||
void proc_readyReadStandardError()
|
||||
{
|
||||
emit q->readyReadStderr();
|
||||
}
|
||||
void GPGProc::Private::proc_error(QProcess::ProcessError x)
|
||||
{
|
||||
QMap<int, QString> errmap;
|
||||
errmap[QProcess::FailedToStart] = "FailedToStart";
|
||||
errmap[QProcess::Crashed] = "Crashed";
|
||||
errmap[QProcess::Timedout] = "Timedout";
|
||||
errmap[QProcess::WriteError] = "WriteError";
|
||||
errmap[QProcess::ReadError] = "ReadError";
|
||||
errmap[QProcess::UnknownError] = "UnknownError";
|
||||
|
||||
void proc_bytesWritten(qint64 lx)
|
||||
{
|
||||
int x = (int)lx;
|
||||
emit q->bytesWrittenStdin(x);
|
||||
}
|
||||
emit q->debug(QString("Process error: %1").arg(errmap[x]));
|
||||
|
||||
void proc_finished(int x)
|
||||
{
|
||||
emit q->debug(QString("Process finished: %1").arg(x));
|
||||
exitCode = x;
|
||||
if(x == QProcess::FailedToStart)
|
||||
error = GPGProc::FailedToStart;
|
||||
else if(x == QProcess::WriteError)
|
||||
error = GPGProc::ErrorWrite;
|
||||
else
|
||||
error = GPGProc::UnexpectedExit;
|
||||
|
||||
fin_process = true;
|
||||
fin_process_success = true;
|
||||
|
||||
if(need_status && !fin_status)
|
||||
{
|
||||
pipeStatus.readEnd().finalize();
|
||||
fin_status = true;
|
||||
if(readAndProcessStatusData())
|
||||
{
|
||||
doneTrigger.start();
|
||||
emit q->readyReadStatusLines();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
doTryDone();
|
||||
}
|
||||
|
||||
void proc_error(QProcess::ProcessError x)
|
||||
{
|
||||
QMap<int, QString> errmap;
|
||||
errmap[QProcess::FailedToStart] = "FailedToStart";
|
||||
errmap[QProcess::Crashed] = "Crashed";
|
||||
errmap[QProcess::Timedout] = "Timedout";
|
||||
errmap[QProcess::WriteError] = "WriteError";
|
||||
errmap[QProcess::ReadError] = "ReadError";
|
||||
errmap[QProcess::UnknownError] = "UnknownError";
|
||||
|
||||
emit q->debug(QString("Process error: %1").arg(errmap[x]));
|
||||
|
||||
if(x == QProcess::FailedToStart)
|
||||
error = GPGProc::FailedToStart;
|
||||
else if(x == QProcess::WriteError)
|
||||
error = GPGProc::ErrorWrite;
|
||||
else
|
||||
error = GPGProc::UnexpectedExit;
|
||||
|
||||
fin_process = true;
|
||||
fin_process_success = false;
|
||||
fin_process = true;
|
||||
fin_process_success = false;
|
||||
|
||||
#ifdef QT_PIPE_HACK
|
||||
// If the process fails to start, then the ends of the pipes
|
||||
// intended for the child process are still open. Some Mac
|
||||
// users experience a lockup if we close our ends of the pipes
|
||||
// when the child's ends are still open. If we ensure the
|
||||
// child's ends are closed, we prevent this lockup. I have no
|
||||
// idea why the problem even happens or why this fix should
|
||||
// work.
|
||||
pipeAux.readEnd().reset();
|
||||
pipeCommand.readEnd().reset();
|
||||
pipeStatus.writeEnd().reset();
|
||||
// If the process fails to start, then the ends of the pipes
|
||||
// intended for the child process are still open. Some Mac
|
||||
// users experience a lockup if we close our ends of the pipes
|
||||
// when the child's ends are still open. If we ensure the
|
||||
// child's ends are closed, we prevent this lockup. I have no
|
||||
// idea why the problem even happens or why this fix should
|
||||
// work.
|
||||
pipeAux.readEnd().reset();
|
||||
pipeCommand.readEnd().reset();
|
||||
pipeStatus.writeEnd().reset();
|
||||
#endif
|
||||
|
||||
if(need_status && !fin_status)
|
||||
if(need_status && !fin_status)
|
||||
{
|
||||
pipeStatus.readEnd().finalize();
|
||||
fin_status = true;
|
||||
if(readAndProcessStatusData())
|
||||
{
|
||||
pipeStatus.readEnd().finalize();
|
||||
fin_status = true;
|
||||
if(readAndProcessStatusData())
|
||||
{
|
||||
doneTrigger.start();
|
||||
emit q->readyReadStatusLines();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
doTryDone();
|
||||
}
|
||||
|
||||
void doTryDone()
|
||||
{
|
||||
if(!fin_process)
|
||||
doneTrigger.start();
|
||||
emit q->readyReadStatusLines();
|
||||
return;
|
||||
|
||||
if(need_status && !fin_status)
|
||||
return;
|
||||
|
||||
emit q->debug("Done");
|
||||
|
||||
// get leftover data
|
||||
proc->setReadChannel(QProcess::StandardOutput);
|
||||
leftover_stdout = proc->readAll();
|
||||
|
||||
proc->setReadChannel(QProcess::StandardError);
|
||||
leftover_stderr = proc->readAll();
|
||||
|
||||
reset(ResetSession);
|
||||
if(fin_process_success)
|
||||
emit q->finished(exitCode);
|
||||
else
|
||||
emit q->error(error);
|
||||
}
|
||||
|
||||
private:
|
||||
bool readAndProcessStatusData()
|
||||
{
|
||||
QByteArray buf = pipeStatus.readEnd().read();
|
||||
if(buf.isEmpty())
|
||||
return false;
|
||||
|
||||
return processStatusData(buf);
|
||||
}
|
||||
|
||||
// return true if there are newly parsed lines available
|
||||
bool processStatusData(const QByteArray &buf)
|
||||
{
|
||||
statusBuf.append(buf);
|
||||
|
||||
// extract all lines
|
||||
QStringList list;
|
||||
while(1)
|
||||
{
|
||||
int n = statusBuf.indexOf('\n');
|
||||
if(n == -1)
|
||||
break;
|
||||
|
||||
// extract the string from statusbuf
|
||||
++n;
|
||||
char *p = (char *)statusBuf.data();
|
||||
QByteArray cs(p, n);
|
||||
int newsize = statusBuf.size() - n;
|
||||
memmove(p, p + n, newsize);
|
||||
statusBuf.resize(newsize);
|
||||
|
||||
// convert to string without newline
|
||||
QString str = QString::fromUtf8(cs);
|
||||
str.truncate(str.length() - 1);
|
||||
|
||||
// ensure it has a proper header
|
||||
if(str.left(9) != "[GNUPG:] ")
|
||||
continue;
|
||||
|
||||
// take it off
|
||||
str = str.mid(9);
|
||||
|
||||
// add to the list
|
||||
list += str;
|
||||
}
|
||||
|
||||
if(list.isEmpty())
|
||||
return false;
|
||||
|
||||
statusLines += list;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
doTryDone();
|
||||
}
|
||||
|
||||
void GPGProc::Private::doTryDone()
|
||||
{
|
||||
if(!fin_process)
|
||||
return;
|
||||
|
||||
if(need_status && !fin_status)
|
||||
return;
|
||||
|
||||
emit q->debug("Done");
|
||||
|
||||
// get leftover data
|
||||
proc->setReadChannel(QProcess::StandardOutput);
|
||||
leftover_stdout = proc->readAll();
|
||||
|
||||
proc->setReadChannel(QProcess::StandardError);
|
||||
leftover_stderr = proc->readAll();
|
||||
|
||||
reset(ResetSession);
|
||||
if(fin_process_success)
|
||||
emit q->finished(exitCode);
|
||||
else
|
||||
emit q->error(error);
|
||||
}
|
||||
|
||||
bool GPGProc::Private::readAndProcessStatusData()
|
||||
{
|
||||
QByteArray buf = pipeStatus.readEnd().read();
|
||||
if(buf.isEmpty())
|
||||
return false;
|
||||
|
||||
return processStatusData(buf);
|
||||
}
|
||||
|
||||
// return true if there are newly parsed lines available
|
||||
bool GPGProc::Private::processStatusData(const QByteArray &buf)
|
||||
{
|
||||
statusBuf.append(buf);
|
||||
|
||||
// extract all lines
|
||||
QStringList list;
|
||||
while(1)
|
||||
{
|
||||
int n = statusBuf.indexOf('\n');
|
||||
if(n == -1)
|
||||
break;
|
||||
|
||||
// extract the string from statusbuf
|
||||
++n;
|
||||
char *p = (char *)statusBuf.data();
|
||||
QByteArray cs(p, n);
|
||||
int newsize = statusBuf.size() - n;
|
||||
memmove(p, p + n, newsize);
|
||||
statusBuf.resize(newsize);
|
||||
|
||||
// convert to string without newline
|
||||
QString str = QString::fromUtf8(cs);
|
||||
str.truncate(str.length() - 1);
|
||||
|
||||
// ensure it has a proper header
|
||||
if(str.left(9) != "[GNUPG:] ")
|
||||
continue;
|
||||
|
||||
// take it off
|
||||
str = str.mid(9);
|
||||
|
||||
// add to the list
|
||||
list += str;
|
||||
}
|
||||
|
||||
if(list.isEmpty())
|
||||
return false;
|
||||
|
||||
statusLines += list;
|
||||
return true;
|
||||
}
|
||||
|
||||
GPGProc::GPGProc(QObject *parent)
|
||||
:QObject(parent)
|
||||
@ -778,5 +680,3 @@ void GPGProc::closeCommand()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "gpgproc.moc"
|
||||
|
156
plugins/qca-gnupg/gpgproc/gpgproc_p.h
Normal file
156
plugins/qca-gnupg/gpgproc/gpgproc_p.h
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define QPROC_SIGNAL_RELAY
|
||||
|
||||
#include "qpipe.h"
|
||||
#include "sprocess.h"
|
||||
#include "gpgproc.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace gpgQCAPlugin {
|
||||
|
||||
class QProcessSignalRelay : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QProcessSignalRelay(QProcess *proc, QObject *parent = 0)
|
||||
:QObject(parent)
|
||||
{
|
||||
qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError");
|
||||
connect(proc, SIGNAL(started()), SLOT(proc_started()), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(readyReadStandardOutput()), SLOT(proc_readyReadStandardOutput()), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(readyReadStandardError()), SLOT(proc_readyReadStandardError()), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(bytesWritten(qint64)), SLOT(proc_bytesWritten(qint64)), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(finished(int)), SLOT(proc_finished(int)), Qt::QueuedConnection);
|
||||
connect(proc, SIGNAL(error(QProcess::ProcessError)), SLOT(proc_error(QProcess::ProcessError)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void readyReadStandardOutput();
|
||||
void readyReadStandardError();
|
||||
void bytesWritten(qint64);
|
||||
void finished(int);
|
||||
void error(QProcess::ProcessError);
|
||||
|
||||
public slots:
|
||||
void proc_started()
|
||||
{
|
||||
emit started();
|
||||
}
|
||||
|
||||
void proc_readyReadStandardOutput()
|
||||
{
|
||||
emit readyReadStandardOutput();
|
||||
}
|
||||
|
||||
void proc_readyReadStandardError()
|
||||
{
|
||||
emit readyReadStandardError();
|
||||
}
|
||||
|
||||
void proc_bytesWritten(qint64 x)
|
||||
{
|
||||
emit bytesWritten(x);
|
||||
}
|
||||
|
||||
void proc_finished(int x)
|
||||
{
|
||||
emit finished(x);
|
||||
}
|
||||
|
||||
void proc_error(QProcess::ProcessError x)
|
||||
{
|
||||
emit error(x);
|
||||
}
|
||||
};
|
||||
|
||||
enum ResetMode
|
||||
{
|
||||
ResetSession = 0,
|
||||
ResetSessionAndData = 1,
|
||||
ResetAll = 2
|
||||
};
|
||||
|
||||
class GPGProc::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GPGProc *q;
|
||||
QString bin;
|
||||
QStringList args;
|
||||
GPGProc::Mode mode;
|
||||
SProcess *proc;
|
||||
#ifdef QPROC_SIGNAL_RELAY
|
||||
QProcessSignalRelay *proc_relay;
|
||||
#endif
|
||||
QCA::QPipe pipeAux, pipeCommand, pipeStatus;
|
||||
QByteArray statusBuf;
|
||||
QStringList statusLines;
|
||||
GPGProc::Error error;
|
||||
int exitCode;
|
||||
QCA::SafeTimer startTrigger, doneTrigger;
|
||||
|
||||
QByteArray pre_stdin, pre_aux;
|
||||
#ifdef QPIPE_SECURE
|
||||
QCA::SecureArray pre_command;
|
||||
#else
|
||||
QByteArray pre_command;
|
||||
#endif
|
||||
bool pre_stdin_close, pre_aux_close, pre_command_close;
|
||||
|
||||
bool need_status, fin_process, fin_process_success, fin_status;
|
||||
QByteArray leftover_stdout;
|
||||
QByteArray leftover_stderr;
|
||||
|
||||
Private(GPGProc *_q);
|
||||
~Private();
|
||||
void closePipes();
|
||||
void reset(ResetMode mode);
|
||||
bool setupPipes(bool makeAux);
|
||||
void setupArguments();
|
||||
|
||||
public slots:
|
||||
void doStart();
|
||||
void aux_written(int x);
|
||||
void aux_error(QCA::QPipeEnd::Error);
|
||||
void command_written(int x);
|
||||
void command_error(QCA::QPipeEnd::Error);
|
||||
void status_read();
|
||||
void status_error(QCA::QPipeEnd::Error e);
|
||||
void proc_started();
|
||||
void proc_readyReadStandardOutput();
|
||||
void proc_readyReadStandardError();
|
||||
void proc_bytesWritten(qint64 lx);
|
||||
void proc_finished(int x);
|
||||
void proc_error(QProcess::ProcessError x);
|
||||
void doTryDone();
|
||||
|
||||
private:
|
||||
bool readAndProcessStatusData();
|
||||
// return true if there are newly parsed lines available
|
||||
bool processStatusData(const QByteArray &buf);
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // end namespace gpgQCAPlugin
|
Loading…
x
Reference in New Issue
Block a user