00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
#include "gnupgprocessbase.h"
00034
00035
#include <kdebug.h>
00036
#include <kurl.h>
00037
00038
#include <qsocketnotifier.h>
00039
#include <qtextcodec.h>
00040
#include <qstringlist.h>
00041
00042
#include <unistd.h>
00043
#include <fcntl.h>
00044
#include <errno.h>
00045
#include <assert.h>
00046
00047
struct Kleo::GnuPGProcessBase::Private {
00048 Private() : useStatusFD( false ), statnot( 0 ) {
00049 statusFD[0] = statusFD[1] = -1;
00050 }
00051
00052
bool useStatusFD;
00053
int statusFD[2];
00054
QSocketNotifier * statnot;
00055
QCString statusBuffer;
00056 };
00057
00058
00059 Kleo::GnuPGProcessBase::GnuPGProcessBase(
QObject * parent,
const char * name )
00060 : KProcess( parent, name )
00061 {
00062 d =
new Private();
00063 }
00064
00065 Kleo::GnuPGProcessBase::~GnuPGProcessBase() {
00066
delete d; d = 0;
00067 }
00068
00069
void Kleo::GnuPGProcessBase::setUseStatusFD(
bool use ) {
00070 assert( d );
00071 d->useStatusFD = use;
00072 }
00073
00074 bool Kleo::GnuPGProcessBase::start( RunMode runmode, Communication comm ) {
00075
if ( d->useStatusFD ) {
00076
00077
00078
00079
00080
if ( ::pipe( d->statusFD ) < 0 ) {
00081 kdDebug( 5150 ) <<
"Kleo::GnuPGProcessBase::start: pipe(2) failed: " << perror << endl;
00082
return false;
00083 }
00084 ::fcntl( d->statusFD[0], F_SETFD, FD_CLOEXEC );
00085 ::fcntl( d->statusFD[1], F_SETFD, FD_CLOEXEC );
00086
if ( !arguments.empty() ) {
00087
QValueList<QCString>::iterator it = arguments.begin();
00088 ++it;
00089 arguments.insert( it,
"--status-fd" );
00090
char buf[25];
00091 sprintf( buf,
"%d", d->statusFD[1] );
00092 arguments.insert( it, buf );
00093 arguments.insert( it,
"--no-tty" );
00094
00095 }
00096 }
00097
return KProcess::start( runmode, comm );
00098 }
00099
00100
int Kleo::GnuPGProcessBase::setupCommunication( Communication comm ) {
00101
if (
int ok = KProcess::setupCommunication( comm ) )
00102
return ok;
00103
if ( d->useStatusFD ) {
00104
00105 ::close( d->statusFD[0] );
00106 ::close( d->statusFD[1] );
00107 d->statusFD[0] = d->statusFD[1] = -1;
00108 }
00109
return 0;
00110 }
00111
00112
int Kleo::GnuPGProcessBase::commSetupDoneP() {
00113
if ( d->useStatusFD ) {
00114 ::close( d->statusFD[1] );
00115 d->statnot =
new QSocketNotifier( d->statusFD[0], QSocketNotifier::Read,
this );
00116 connect( d->statnot, SIGNAL(activated(
int)), SLOT(slotChildStatus(
int)) );
00117 }
00118
return KProcess::commSetupDoneP();
00119 }
00120
00121
int Kleo::GnuPGProcessBase::commSetupDoneC() {
00122
if ( d->useStatusFD )
00123 ::fcntl( d->statusFD[1], F_SETFD, 0 );
00124
return KProcess::commSetupDoneC();
00125 }
00126
00127
void Kleo::GnuPGProcessBase::slotChildStatus(
int fd ) {
00128
if ( !childStatus(fd) )
00129 closeStatus();
00130 }
00131
00132
bool Kleo::GnuPGProcessBase::closeStatus() {
00133
if ( !d->useStatusFD )
00134
return false;
00135 d->useStatusFD =
false;
00136
delete d->statnot; d->statnot = 0;
00137 ::close( d->statusFD[0] ); d->statusFD[0] = -1;
00138
return true;
00139 }
00140
00141
int Kleo::GnuPGProcessBase::childStatus(
int fd ) {
00142
char buf[1024];
00143
const int len = ::read( fd, buf,
sizeof(buf)-1 );
00144
if ( len > 0 ) {
00145 buf[len] = 0;
00146 d->statusBuffer += buf;
00147 parseStatusOutput();
00148 }
00149
return len;
00150 }
00151
00152
static QString fromHexEscapedUtf8(
const QCString & str ) {
00153
return KURL::decode_string( str.data(), 106 );
00154 }
00155
00156
void Kleo::GnuPGProcessBase::parseStatusOutput() {
00157
static const char startToken[] =
"[GNUPG:] ";
00158
static const int startTokenLen =
sizeof startToken /
sizeof *startToken - 1;
00159
00160
int lineStart = 0;
00161
for (
int lineEnd = d->statusBuffer.find(
'\n' ) ; lineEnd >= 0 ; lineEnd = d->statusBuffer.find(
'\n', lineStart = lineEnd+1 ) ) {
00162
00163
const QCString line = d->statusBuffer.mid( lineStart, lineEnd - lineStart ).stripWhiteSpace();
00164
if ( line.isEmpty() )
00165
continue;
00166
00167
if ( line.left( startTokenLen ) != startToken ) {
00168 kdDebug( 5150 ) <<
"Kleo::GnuPGProcessBase::childStatus: status-fd protocol error: line doesn't begin with \""
00169 << startToken <<
"\"" << endl;
00170
continue;
00171 }
00172
00173
const QCString command = line.mid( startTokenLen ).simplifyWhiteSpace() +
' ';
00174
if ( command ==
" " ) {
00175 kdDebug( 5150 ) <<
"Kleo::GnuPGProcessBase::childStatus: status-fd protocol error: line without content." << endl;
00176
continue;
00177 }
00178
00179
QString cmd;
00180
QStringList args;
00181
int tagStart = 0;
00182
for (
int tagEnd = command.find(
' ' ) ; tagEnd >= 0 ; tagEnd = command.find(
' ', tagStart = tagEnd+1 ) ) {
00183
const QCString tag = command.mid( tagStart, tagEnd - tagStart );
00184
if ( cmd.isNull() )
00185 cmd = fromHexEscapedUtf8( tag );
00186
else
00187 args.push_back( fromHexEscapedUtf8( tag ) );
00188 }
00189 emit status(
this, cmd, args );
00190 }
00191 d->statusBuffer = d->statusBuffer.mid( lineStart );
00192 }
00193
00194 void Kleo::GnuPGProcessBase::virtual_hook(
int id,
void * data ) {
00195 KProcess::virtual_hook(
id, data );
00196 }
00197
00198
#include "gnupgprocessbase.moc"