certmanager/lib
gnupgprocessbase.cpp00001
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"
|