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 <tqsocketnotifier.h>
00039 #include <tqtextcodec.h>
00040 #include <tqstringlist.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() : usetStatusFD( false ), statnot( 0 ) {
00049 statusFD[0] = statusFD[1] = -1;
00050 }
00051
00052 bool usetStatusFD;
00053 int statusFD[2];
00054 TQSocketNotifier * statnot;
00055 TQCString statusBuffer;
00056 };
00057
00058
00059 Kleo::GnuPGProcessBase::GnuPGProcessBase( TQObject * parent, const char * name )
00060 : TDEProcess( parent, name )
00061 {
00062 d = new Private();
00063 }
00064
00065 Kleo::GnuPGProcessBase::~GnuPGProcessBase() {
00066 delete d; d = 0;
00067 }
00068
00069 void Kleo::GnuPGProcessBase::setUsetStatusFD( bool use ) {
00070 assert( d );
00071 d->usetStatusFD = use;
00072 }
00073
00074 bool Kleo::GnuPGProcessBase::start( RunMode runmode, Communication comm ) {
00075 if ( d->usetStatusFD ) {
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 TQValueList<TQCString>::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 TDEProcess::start( runmode, comm );
00098 }
00099
00100 int Kleo::GnuPGProcessBase::setupCommunication( Communication comm ) {
00101 if ( int ok = TDEProcess::setupCommunication( comm ) )
00102 return ok;
00103 if ( d->usetStatusFD ) {
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->usetStatusFD ) {
00114 ::close( d->statusFD[1] );
00115 d->statnot = new TQSocketNotifier( d->statusFD[0], TQSocketNotifier::Read, this );
00116 connect( d->statnot, TQT_SIGNAL(activated(int)), TQT_SLOT(slotChildStatus(int)) );
00117 }
00118 return TDEProcess::commSetupDoneP();
00119 }
00120
00121 int Kleo::GnuPGProcessBase::commSetupDoneC() {
00122 if ( d->usetStatusFD )
00123 ::fcntl( d->statusFD[1], F_SETFD, 0 );
00124 return TDEProcess::commSetupDoneC();
00125 }
00126
00127 void Kleo::GnuPGProcessBase::slotChildStatus( int fd ) {
00128 if ( !childStatus(fd) )
00129 closetStatus();
00130 }
00131
00132 bool Kleo::GnuPGProcessBase::closetStatus() {
00133 if ( !d->usetStatusFD )
00134 return false;
00135 d->usetStatusFD = 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 parsetStatusOutput();
00148 }
00149 return len;
00150 }
00151
00152 static TQString fromHexEscapedUtf8( const TQCString & str ) {
00153 return KURL::decode_string( str.data(), 106 );
00154 }
00155
00156 void Kleo::GnuPGProcessBase::parsetStatusOutput() {
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 TQCString 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 TQCString 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 TQString cmd;
00180 TQStringList args;
00181 int tagStart = 0;
00182 for ( int tagEnd = command.find( ' ' ) ; tagEnd >= 0 ; tagEnd = command.find( ' ', tagStart = tagEnd+1 ) ) {
00183 const TQCString 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 TDEProcess::virtual_hook( id, data );
00196 }
00197
00198 #include "gnupgprocessbase.moc"