2005-06-05 08:45:48 +00:00
|
|
|
/*
|
2007-06-05 19:08:11 +00:00
|
|
|
* Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
|
2005-06-05 08:45:48 +00:00
|
|
|
*
|
|
|
|
* 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
|
2007-01-02 06:19:41 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-06-05 08:45:48 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
#include "gpgproc_p.h"
|
2006-03-30 09:41:01 +00:00
|
|
|
|
2007-06-05 19:08:11 +00:00
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
#define QT_PIPE_HACK
|
|
|
|
#endif
|
|
|
|
|
2007-08-20 17:35:27 +00:00
|
|
|
|
2006-03-30 09:41:01 +00:00
|
|
|
using namespace QCA;
|
2005-06-05 08:45:48 +00:00
|
|
|
|
|
|
|
namespace gpgQCAPlugin {
|
|
|
|
|
2008-04-07 06:27:05 +00:00
|
|
|
void releaseAndDeleteLater(QObject *owner, QObject *obj)
|
|
|
|
{
|
|
|
|
obj->disconnect(owner);
|
2020-02-12 17:14:33 +01:00
|
|
|
obj->setParent(nullptr);
|
2008-04-07 06:27:05 +00:00
|
|
|
obj->deleteLater();
|
|
|
|
}
|
|
|
|
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
GPGProc::Private::Private(GPGProc *_q)
|
|
|
|
: QObject(_q)
|
|
|
|
, q(_q)
|
|
|
|
, pipeAux(this)
|
|
|
|
, pipeCommand(this)
|
|
|
|
, pipeStatus(this)
|
|
|
|
, startTrigger(this)
|
|
|
|
, doneTrigger(this)
|
|
|
|
{
|
|
|
|
qRegisterMetaType<gpgQCAPlugin::GPGProc::Error>("gpgQCAPlugin::GPGProc::Error");
|
2006-03-30 09:41:01 +00:00
|
|
|
|
2020-02-12 17:14:33 +01:00
|
|
|
proc = nullptr;
|
|
|
|
proc_relay = nullptr;
|
2014-10-07 02:49:27 +06:00
|
|
|
startTrigger.setSingleShot(true);
|
|
|
|
doneTrigger.setSingleShot(true);
|
|
|
|
|
2020-01-27 16:22:21 +01:00
|
|
|
connect(&pipeAux.writeEnd(), &QCA::QPipeEnd::bytesWritten, this, &GPGProc::Private::aux_written);
|
|
|
|
connect(&pipeAux.writeEnd(), &QCA::QPipeEnd::error, this, &GPGProc::Private::aux_error);
|
|
|
|
connect(&pipeCommand.writeEnd(), &QCA::QPipeEnd::bytesWritten, this, &GPGProc::Private::command_written);
|
|
|
|
connect(&pipeCommand.writeEnd(), &QCA::QPipeEnd::error, this, &GPGProc::Private::command_error);
|
|
|
|
connect(&pipeStatus.readEnd(), &QCA::QPipeEnd::readyRead, this, &GPGProc::Private::status_read);
|
|
|
|
connect(&pipeStatus.readEnd(), &QCA::QPipeEnd::error, this, &GPGProc::Private::status_error);
|
|
|
|
connect(&startTrigger, &QCA::SafeTimer::timeout, this, &GPGProc::Private::doStart);
|
|
|
|
connect(&doneTrigger, &QCA::SafeTimer::timeout, this, &GPGProc::Private::doTryDone);
|
2014-10-07 02:49:27 +06:00
|
|
|
|
|
|
|
reset(ResetSessionAndData);
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
GPGProc::Private::~Private()
|
|
|
|
{
|
|
|
|
reset(ResetSession);
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::closePipes()
|
|
|
|
{
|
2007-05-10 21:46:52 +00:00
|
|
|
#ifdef QT_PIPE_HACK
|
2014-10-07 02:49:27 +06:00
|
|
|
pipeAux.readEnd().reset();
|
|
|
|
pipeCommand.readEnd().reset();
|
|
|
|
pipeStatus.writeEnd().reset();
|
2007-05-10 21:46:52 +00:00
|
|
|
#endif
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
pipeAux.reset();
|
|
|
|
pipeCommand.reset();
|
|
|
|
pipeStatus.reset();
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::reset(ResetMode mode)
|
|
|
|
{
|
2007-05-10 21:46:52 +00:00
|
|
|
#ifndef QT_PIPE_HACK
|
2014-10-07 02:49:27 +06:00
|
|
|
closePipes();
|
2007-05-10 21:46:52 +00:00
|
|
|
#endif
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
if(proc)
|
|
|
|
{
|
|
|
|
proc->disconnect(this);
|
|
|
|
|
|
|
|
if(proc->state() != QProcess::NotRunning)
|
2005-06-05 08:45:48 +00:00
|
|
|
{
|
2014-10-07 02:49:27 +06:00
|
|
|
// Before try to correct end proccess
|
|
|
|
// Terminate if failed
|
|
|
|
proc->close();
|
|
|
|
bool finished = proc->waitForFinished(5000);
|
|
|
|
if (!finished)
|
|
|
|
proc->terminate();
|
|
|
|
}
|
|
|
|
|
2020-02-12 17:14:33 +01:00
|
|
|
proc->setParent(nullptr);
|
2014-10-07 02:49:27 +06:00
|
|
|
releaseAndDeleteLater(this, proc_relay);
|
2020-02-12 17:14:33 +01:00
|
|
|
proc_relay = nullptr;
|
2014-10-07 02:49:27 +06:00
|
|
|
delete proc; // should be safe to do thanks to relay
|
2020-02-12 17:14:33 +01:00
|
|
|
proc = nullptr;
|
2014-10-07 02:49:27 +06:00
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2007-05-10 21:46:52 +00:00
|
|
|
#ifdef QT_PIPE_HACK
|
2014-10-07 02:49:27 +06:00
|
|
|
closePipes();
|
2007-05-10 21:46:52 +00:00
|
|
|
#endif
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
startTrigger.stop();
|
|
|
|
doneTrigger.stop();
|
2005-06-18 18:08:09 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
pre_stdin.clear();
|
|
|
|
pre_aux.clear();
|
|
|
|
pre_command.clear();
|
|
|
|
pre_stdin_close = false;
|
|
|
|
pre_aux_close = false;
|
|
|
|
pre_command_close = false;
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
need_status = false;
|
|
|
|
fin_process = false;
|
|
|
|
fin_status = false;
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
if(mode >= ResetSessionAndData)
|
|
|
|
{
|
|
|
|
statusBuf.clear();
|
|
|
|
statusLines.clear();
|
|
|
|
leftover_stdout.clear();
|
|
|
|
leftover_stderr.clear();
|
|
|
|
error = GPGProc::FailedToStart;
|
|
|
|
exitCode = -1;
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
2014-10-07 02:49:27 +06:00
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
bool GPGProc::Private::setupPipes(bool makeAux)
|
|
|
|
{
|
|
|
|
if(makeAux && !pipeAux.create())
|
2005-06-05 08:45:48 +00:00
|
|
|
{
|
2014-10-07 02:49:27 +06:00
|
|
|
closePipes();
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Error creating pipeAux"));
|
2014-10-07 02:49:27 +06:00
|
|
|
return false;
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
|
|
|
#ifdef QPIPE_SECURE
|
2014-10-07 02:49:27 +06:00
|
|
|
if(!pipeCommand.create(true)) // secure
|
2005-06-05 08:45:48 +00:00
|
|
|
#else
|
|
|
|
if(!pipeCommand.create())
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
closePipes();
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Error creating pipeCommand"));
|
2005-06-05 08:45:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
if(!pipeStatus.create())
|
2007-05-31 22:47:25 +00:00
|
|
|
{
|
2014-10-07 02:49:27 +06:00
|
|
|
closePipes();
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Error creating pipeStatus"));
|
2014-10-07 02:49:27 +06:00
|
|
|
return false;
|
|
|
|
}
|
2007-05-31 22:47:25 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
return true;
|
|
|
|
}
|
2007-05-31 22:47:25 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::setupArguments()
|
|
|
|
{
|
|
|
|
QStringList fullargs;
|
2020-02-10 00:29:23 +01:00
|
|
|
fullargs += QStringLiteral("--no-tty");
|
|
|
|
fullargs += QStringLiteral("--pinentry-mode");
|
|
|
|
fullargs += QStringLiteral("loopback");
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
if(mode == ExtendedMode)
|
|
|
|
{
|
2020-02-10 00:29:23 +01:00
|
|
|
fullargs += QStringLiteral("--enable-special-filenames");
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2020-02-10 00:29:23 +01:00
|
|
|
fullargs += QStringLiteral("--status-fd");
|
2014-10-07 02:49:27 +06:00
|
|
|
fullargs += QString::number(pipeStatus.writeEnd().idAsInt());
|
2007-05-31 22:47:25 +00:00
|
|
|
|
2020-02-10 00:29:23 +01:00
|
|
|
fullargs += QStringLiteral("--command-fd");
|
2014-10-07 02:49:27 +06:00
|
|
|
fullargs += QString::number(pipeCommand.readEnd().idAsInt());
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
for(int n = 0; n < args.count(); ++n)
|
2005-07-06 22:17:57 +00:00
|
|
|
{
|
2014-10-07 02:49:27 +06:00
|
|
|
QString a = args[n];
|
2020-02-10 00:29:23 +01:00
|
|
|
if(mode == ExtendedMode && a == QLatin1String("-&?"))
|
|
|
|
fullargs += QStringLiteral("-&") + QString::number(pipeAux.readEnd().idAsInt());
|
2014-10-07 02:49:27 +06:00
|
|
|
else
|
|
|
|
fullargs += a;
|
|
|
|
}
|
|
|
|
|
2020-02-10 00:29:23 +01:00
|
|
|
QString fullcmd = fullargs.join(QStringLiteral(" "));
|
2020-02-13 00:59:09 +01:00
|
|
|
emit q->debug(QStringLiteral("Running: [") + bin + QLatin1Char(' ') + fullcmd + QLatin1Char(']'));
|
2014-10-07 02:49:27 +06:00
|
|
|
|
|
|
|
args = fullargs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::Private::doStart()
|
|
|
|
{
|
2007-05-31 22:47:25 +00:00
|
|
|
#ifdef Q_OS_WIN
|
2014-10-07 02:49:27 +06:00
|
|
|
// 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);
|
2007-05-31 22:47:25 +00:00
|
|
|
#endif
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
setupArguments();
|
2007-05-31 22:47:25 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
proc->start(bin, args);
|
|
|
|
proc->waitForStarted();
|
2007-05-31 22:47:25 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
pipeAux.readEnd().close();
|
|
|
|
pipeCommand.readEnd().close();
|
|
|
|
pipeStatus.writeEnd().close();
|
|
|
|
}
|
2005-07-06 22:17:57 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::aux_written(int x)
|
|
|
|
{
|
|
|
|
emit q->bytesWrittenAux(x);
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::aux_error(QCA::QPipeEnd::Error)
|
|
|
|
{
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Aux: Pipe error"));
|
2014-10-07 02:49:27 +06:00
|
|
|
reset(ResetSession);
|
|
|
|
emit q->error(GPGProc::ErrorWrite);
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::command_written(int x)
|
|
|
|
{
|
|
|
|
emit q->bytesWrittenCommand(x);
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::command_error(QCA::QPipeEnd::Error)
|
|
|
|
{
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Command: Pipe error"));
|
2014-10-07 02:49:27 +06:00
|
|
|
reset(ResetSession);
|
|
|
|
emit q->error(GPGProc::ErrorWrite);
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::status_read()
|
|
|
|
{
|
|
|
|
if(readAndProcessStatusData())
|
|
|
|
emit q->readyReadStatusLines();
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::status_error(QCA::QPipeEnd::Error e)
|
|
|
|
{
|
|
|
|
if(e == QPipeEnd::ErrorEOF)
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Status: Closed (EOF)"));
|
2014-10-07 02:49:27 +06:00
|
|
|
else
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Status: Closed (gone)"));
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
fin_status = true;
|
|
|
|
doTryDone();
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::proc_started()
|
|
|
|
{
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Process started"));
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
// 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();*/
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
// 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())
|
|
|
|
{
|
2005-06-05 08:45:48 +00:00
|
|
|
#ifdef QPIPE_SECURE
|
2014-10-07 02:49:27 +06:00
|
|
|
pipeCommand.writeEnd().writeSecure(pre_command);
|
2005-06-05 08:45:48 +00:00
|
|
|
#else
|
2014-10-07 02:49:27 +06:00
|
|
|
pipeCommand.writeEnd().write(pre_command);
|
2005-06-05 08:45:48 +00:00
|
|
|
#endif
|
2014-10-07 02:49:27 +06:00
|
|
|
pre_command.clear();
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
if(pre_stdin_close)
|
2005-06-05 08:45:48 +00:00
|
|
|
{
|
2014-10-07 02:49:27 +06:00
|
|
|
proc->waitForBytesWritten();
|
|
|
|
proc->closeWriteChannel();
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
if(pre_aux_close)
|
|
|
|
pipeAux.writeEnd().close();
|
|
|
|
if(pre_command_close)
|
|
|
|
pipeCommand.writeEnd().close();
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::proc_readyReadStandardOutput()
|
|
|
|
{
|
|
|
|
emit q->readyReadStdout();
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::proc_readyReadStandardError()
|
|
|
|
{
|
|
|
|
emit q->readyReadStderr();
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::proc_bytesWritten(qint64 lx)
|
|
|
|
{
|
|
|
|
int x = (int)lx;
|
|
|
|
emit q->bytesWrittenStdin(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::Private::proc_finished(int x)
|
|
|
|
{
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Process finished: %1").arg(x));
|
2014-10-07 02:49:27 +06:00
|
|
|
exitCode = x;
|
2005-06-18 18:08:09 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
fin_process = true;
|
|
|
|
fin_process_success = true;
|
|
|
|
|
|
|
|
if(need_status && !fin_status)
|
|
|
|
{
|
|
|
|
pipeStatus.readEnd().finalize();
|
|
|
|
fin_status = true;
|
|
|
|
if(readAndProcessStatusData())
|
2005-06-18 18:08:09 +00:00
|
|
|
{
|
2014-10-07 02:49:27 +06:00
|
|
|
doneTrigger.start();
|
|
|
|
emit q->readyReadStatusLines();
|
|
|
|
return;
|
2005-06-18 18:08:09 +00:00
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
doTryDone();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::Private::proc_error(QProcess::ProcessError x)
|
|
|
|
{
|
|
|
|
QMap<int, QString> errmap;
|
2020-02-10 00:29:23 +01:00
|
|
|
errmap[QProcess::FailedToStart] = QStringLiteral("FailedToStart");
|
|
|
|
errmap[QProcess::Crashed] = QStringLiteral("Crashed");
|
|
|
|
errmap[QProcess::Timedout] = QStringLiteral("Timedout");
|
|
|
|
errmap[QProcess::WriteError] = QStringLiteral("WriteError");
|
|
|
|
errmap[QProcess::ReadError] = QStringLiteral("ReadError");
|
|
|
|
errmap[QProcess::UnknownError] = QStringLiteral("UnknownError");
|
2014-10-07 02:49:27 +06:00
|
|
|
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Process error: %1").arg(errmap[x]));
|
2014-10-07 02:49:27 +06:00
|
|
|
|
|
|
|
if(x == QProcess::FailedToStart)
|
|
|
|
error = GPGProc::FailedToStart;
|
|
|
|
else if(x == QProcess::WriteError)
|
|
|
|
error = GPGProc::ErrorWrite;
|
|
|
|
else
|
|
|
|
error = GPGProc::UnexpectedExit;
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
fin_process = true;
|
|
|
|
fin_process_success = false;
|
2005-06-18 18:08:09 +00:00
|
|
|
|
2007-05-10 21:46:52 +00:00
|
|
|
#ifdef QT_PIPE_HACK
|
2014-10-07 02:49:27 +06:00
|
|
|
// 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();
|
2007-04-02 16:22:44 +00:00
|
|
|
#endif
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
if(need_status && !fin_status)
|
|
|
|
{
|
|
|
|
pipeStatus.readEnd().finalize();
|
|
|
|
fin_status = true;
|
|
|
|
if(readAndProcessStatusData())
|
2005-06-18 18:08:09 +00:00
|
|
|
{
|
2014-10-07 02:49:27 +06:00
|
|
|
doneTrigger.start();
|
|
|
|
emit q->readyReadStatusLines();
|
|
|
|
return;
|
2005-06-18 18:08:09 +00:00
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
doTryDone();
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
void GPGProc::Private::doTryDone()
|
|
|
|
{
|
|
|
|
if(!fin_process)
|
|
|
|
return;
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
if(need_status && !fin_status)
|
|
|
|
return;
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2020-02-10 00:29:23 +01:00
|
|
|
emit q->debug(QStringLiteral("Done"));
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
// get leftover data
|
|
|
|
proc->setReadChannel(QProcess::StandardOutput);
|
|
|
|
leftover_stdout = proc->readAll();
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
proc->setReadChannel(QProcess::StandardError);
|
|
|
|
leftover_stderr = proc->readAll();
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
reset(ResetSession);
|
|
|
|
if(fin_process_success)
|
|
|
|
emit q->finished(exitCode);
|
|
|
|
else
|
|
|
|
emit q->error(error);
|
|
|
|
}
|
2005-06-18 18:08:09 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
bool GPGProc::Private::readAndProcessStatusData()
|
|
|
|
{
|
|
|
|
QByteArray buf = pipeStatus.readEnd().read();
|
|
|
|
if(buf.isEmpty())
|
|
|
|
return false;
|
2005-06-18 18:08:09 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
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;
|
2020-01-30 17:24:31 +01:00
|
|
|
while(true)
|
2005-06-05 08:45:48 +00:00
|
|
|
{
|
2014-10-07 02:49:27 +06:00
|
|
|
int n = statusBuf.indexOf('\n');
|
|
|
|
if(n == -1)
|
|
|
|
break;
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
// 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);
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
// convert to string without newline
|
|
|
|
QString str = QString::fromUtf8(cs);
|
|
|
|
str.truncate(str.length() - 1);
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2014-10-07 02:49:27 +06:00
|
|
|
// ensure it has a proper header
|
2020-02-10 00:29:23 +01:00
|
|
|
if(str.left(9) != QLatin1String("[GNUPG:] "))
|
2014-10-07 02:49:27 +06:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// take it off
|
|
|
|
str = str.mid(9);
|
|
|
|
|
|
|
|
// add to the list
|
|
|
|
list += str;
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
2014-10-07 02:49:27 +06:00
|
|
|
|
|
|
|
if(list.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
statusLines += list;
|
|
|
|
return true;
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2005-07-02 02:01:09 +00:00
|
|
|
GPGProc::GPGProc(QObject *parent)
|
|
|
|
:QObject(parent)
|
2005-06-05 08:45:48 +00:00
|
|
|
{
|
|
|
|
d = new Private(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
GPGProc::~GPGProc()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::reset()
|
|
|
|
{
|
|
|
|
d->reset(ResetAll);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GPGProc::isActive() const
|
|
|
|
{
|
|
|
|
return (d->proc ? true : false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::start(const QString &bin, const QStringList &args, Mode mode)
|
|
|
|
{
|
|
|
|
if(isActive())
|
|
|
|
d->reset(ResetSessionAndData);
|
|
|
|
|
2005-06-11 04:41:39 +00:00
|
|
|
if(mode == ExtendedMode)
|
2005-06-05 08:45:48 +00:00
|
|
|
{
|
2020-02-10 00:29:23 +01:00
|
|
|
if(!d->setupPipes(args.contains(QStringLiteral("-&?"))))
|
2005-06-11 04:41:39 +00:00
|
|
|
{
|
|
|
|
d->error = FailedToStart;
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2005-06-11 04:41:39 +00:00
|
|
|
// emit later
|
2006-03-30 09:41:01 +00:00
|
|
|
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(gpgQCAPlugin::GPGProc::Error, d->error));
|
2005-06-11 04:41:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
|
|
|
|
d->need_status = true;
|
|
|
|
|
2020-02-10 00:29:23 +01:00
|
|
|
emit debug(QStringLiteral("Pipe setup complete"));
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
2005-07-02 02:01:09 +00:00
|
|
|
d->proc = new SProcess(d);
|
2005-06-05 08:45:48 +00:00
|
|
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
QList<int> plist;
|
2007-05-31 22:47:25 +00:00
|
|
|
if(d->pipeAux.readEnd().isValid())
|
|
|
|
plist += d->pipeAux.readEnd().id();
|
|
|
|
if(d->pipeCommand.readEnd().isValid())
|
|
|
|
plist += d->pipeCommand.readEnd().id();
|
|
|
|
if(d->pipeStatus.writeEnd().isValid())
|
|
|
|
plist += d->pipeStatus.writeEnd().id();
|
|
|
|
d->proc->setInheritPipeList(plist);
|
2005-06-05 08:45:48 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// enable the pipes we want
|
2005-06-11 04:41:39 +00:00
|
|
|
if(d->pipeAux.writeEnd().isValid())
|
|
|
|
d->pipeAux.writeEnd().enable();
|
|
|
|
if(d->pipeCommand.writeEnd().isValid())
|
|
|
|
d->pipeCommand.writeEnd().enable();
|
|
|
|
if(d->pipeStatus.readEnd().isValid())
|
|
|
|
d->pipeStatus.readEnd().enable();
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2007-05-10 21:46:52 +00:00
|
|
|
d->proc_relay = new QProcessSignalRelay(d->proc, d);
|
2020-01-27 16:22:21 +01:00
|
|
|
connect(d->proc_relay, &QProcessSignalRelay::started, d, &GPGProc::Private::proc_started);
|
|
|
|
connect(d->proc_relay, &QProcessSignalRelay::readyReadStandardOutput, d, &GPGProc::Private::proc_readyReadStandardOutput);
|
|
|
|
connect(d->proc_relay, &QProcessSignalRelay::readyReadStandardError, d, &GPGProc::Private::proc_readyReadStandardError);
|
|
|
|
connect(d->proc_relay, &QProcessSignalRelay::bytesWritten, d, &GPGProc::Private::proc_bytesWritten);
|
|
|
|
connect(d->proc_relay, &QProcessSignalRelay::finished, d, &GPGProc::Private::proc_finished);
|
|
|
|
connect(d->proc_relay, &QProcessSignalRelay::error, d, &GPGProc::Private::proc_error);
|
2005-06-05 08:45:48 +00:00
|
|
|
|
2005-07-06 22:17:57 +00:00
|
|
|
d->bin = bin;
|
2007-05-31 22:47:25 +00:00
|
|
|
d->args = args;
|
|
|
|
d->mode = mode;
|
2005-07-06 22:17:57 +00:00
|
|
|
d->startTrigger.start();
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray GPGProc::readStdout()
|
|
|
|
{
|
|
|
|
if(d->proc)
|
|
|
|
{
|
|
|
|
d->proc->setReadChannel(QProcess::StandardOutput);
|
|
|
|
return d->proc->readAll();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QByteArray a = d->leftover_stdout;
|
|
|
|
d->leftover_stdout.clear();
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray GPGProc::readStderr()
|
|
|
|
{
|
|
|
|
if(d->proc)
|
|
|
|
{
|
|
|
|
d->proc->setReadChannel(QProcess::StandardError);
|
|
|
|
return d->proc->readAll();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QByteArray a = d->leftover_stderr;
|
|
|
|
d->leftover_stderr.clear();
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList GPGProc::readStatusLines()
|
|
|
|
{
|
|
|
|
QStringList out = d->statusLines;
|
|
|
|
d->statusLines.clear();
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::writeStdin(const QByteArray &a)
|
|
|
|
{
|
|
|
|
if(!d->proc || a.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(d->proc->state() == QProcess::Running)
|
|
|
|
d->proc->write(a);
|
|
|
|
else
|
|
|
|
d->pre_stdin += a;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::writeAux(const QByteArray &a)
|
|
|
|
{
|
|
|
|
if(!d->proc || a.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(d->proc->state() == QProcess::Running)
|
|
|
|
d->pipeAux.writeEnd().write(a);
|
|
|
|
else
|
|
|
|
d->pre_aux += a;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef QPIPE_SECURE
|
2007-04-14 01:16:13 +00:00
|
|
|
void GPGProc::writeCommand(const SecureArray &a)
|
2005-06-05 08:45:48 +00:00
|
|
|
#else
|
|
|
|
void GPGProc::writeCommand(const QByteArray &a)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
if(!d->proc || a.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(d->proc->state() == QProcess::Running)
|
|
|
|
#ifdef QPIPE_SECURE
|
|
|
|
d->pipeCommand.writeEnd().writeSecure(a);
|
|
|
|
#else
|
|
|
|
d->pipeCommand.writeEnd().write(a);
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
d->pre_command += a;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::closeStdin()
|
|
|
|
{
|
|
|
|
if(!d->proc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(d->proc->state() == QProcess::Running)
|
2014-09-30 04:58:15 +06:00
|
|
|
{
|
|
|
|
d->proc->waitForBytesWritten();
|
2005-06-05 08:45:48 +00:00
|
|
|
d->proc->closeWriteChannel();
|
2014-09-30 04:58:15 +06:00
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
else
|
2014-09-30 04:58:15 +06:00
|
|
|
{
|
2005-06-05 08:45:48 +00:00
|
|
|
d->pre_stdin_close = true;
|
2014-09-30 04:58:15 +06:00
|
|
|
}
|
2005-06-05 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::closeAux()
|
|
|
|
{
|
|
|
|
if(!d->proc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(d->proc->state() == QProcess::Running)
|
|
|
|
d->pipeAux.writeEnd().close();
|
|
|
|
else
|
|
|
|
d->pre_aux_close = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPGProc::closeCommand()
|
|
|
|
{
|
|
|
|
if(!d->proc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(d->proc->state() == QProcess::Running)
|
|
|
|
d->pipeCommand.writeEnd().close();
|
|
|
|
else
|
|
|
|
d->pre_command_close = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|