38 #include <QSocketNotifier>
40 #include <QStringList>
50 struct Kleo::GnuPGProcessBase::Private {
51 Private() : useStatusFD( false ), statnot( 0 ) {
52 statusFD[0] = statusFD[1] = -1;
57 QSocketNotifier * statnot;
58 QByteArray statusBuffer;
78 bool Kleo::GnuPGProcessBase::start( RunMode runmode, Communication comm ) {
79 if ( d->useStatusFD ) {
84 if ( ::pipe( d->statusFD ) < 0 ) {
85 kDebug( 5150 ) <<
"Kleo::GnuPGProcessBase::start: pipe(2) failed:" << perror;
88 ::fcntl( d->statusFD[0], F_SETFD, FD_CLOEXEC );
89 ::fcntl( d->statusFD[1], F_SETFD, FD_CLOEXEC );
90 if ( !arguments.empty() ) {
91 QList<QByteArray>::iterator it = arguments.begin();
93 arguments.insert( it,
"--status-fd" );
95 sprintf( buf,
"%d", d->statusFD[1] );
96 arguments.insert( it, buf );
97 arguments.insert( it,
"--no-tty" );
101 return K3Process::start( runmode, comm );
104 int Kleo::GnuPGProcessBase::setupCommunication( Communication comm ) {
105 if (
int ok = K3Process::setupCommunication( comm ) )
107 if ( d->useStatusFD ) {
109 ::close( d->statusFD[0] );
110 ::close( d->statusFD[1] );
111 d->statusFD[0] = d->statusFD[1] = -1;
116 int Kleo::GnuPGProcessBase::commSetupDoneP() {
117 if ( d->useStatusFD ) {
118 ::close( d->statusFD[1] );
119 d->statnot =
new QSocketNotifier( d->statusFD[0], QSocketNotifier::Read,
this );
120 connect( d->statnot, SIGNAL(activated(
int)), SLOT(slotChildStatus(
int)) );
122 return K3Process::commSetupDoneP();
125 int Kleo::GnuPGProcessBase::commSetupDoneC() {
126 if ( d->useStatusFD )
127 ::fcntl( d->statusFD[1], F_SETFD, 0 );
128 return K3Process::commSetupDoneC();
131 void Kleo::GnuPGProcessBase::slotChildStatus(
int fd ) {
132 if ( !childStatus(fd) )
136 bool Kleo::GnuPGProcessBase::closeStatus() {
137 if ( !d->useStatusFD )
139 d->useStatusFD =
false;
140 delete d->statnot; d->statnot = 0;
141 ::close( d->statusFD[0] ); d->statusFD[0] = -1;
145 int Kleo::GnuPGProcessBase::childStatus(
int fd ) {
147 const int len = ::read( fd, buf,
sizeof(buf)-1 );
150 d->statusBuffer += buf;
156 static QString fromHexEscapedUtf8(
const QByteArray & str ) {
157 return KUrl::fromPercentEncoding( str.data() );
160 void Kleo::GnuPGProcessBase::parseStatusOutput() {
161 static const char startToken[] =
"[GNUPG:] ";
162 static const int startTokenLen =
sizeof startToken /
sizeof *startToken - 1;
165 for (
int lineEnd = d->statusBuffer.indexOf(
'\n' ) ; lineEnd >= 0 ; lineEnd = d->statusBuffer.indexOf(
'\n', lineStart = lineEnd+1 ) ) {
167 const QByteArray line = d->statusBuffer.mid( lineStart, lineEnd - lineStart ).trimmed();
168 if ( line.isEmpty() )
171 if ( line.left( startTokenLen ) != startToken ) {
172 kDebug( 5150 ) <<
"Kleo::GnuPGProcessBase::childStatus: status-fd protocol error: line doesn't begin with \""
173 << startToken <<
"\"";
177 const QByteArray command = line.mid( startTokenLen ).simplified() +
' ';
178 if ( command ==
" " ) {
179 kDebug( 5150 ) <<
"Kleo::GnuPGProcessBase::childStatus: status-fd protocol error: line without content.";
186 for (
int tagEnd = command.indexOf(
' ' ) ; tagEnd >= 0 ; tagEnd = command.indexOf(
' ', tagStart = tagEnd+1 ) ) {
187 const QByteArray tag = command.mid( tagStart, tagEnd - tagStart );
189 cmd = fromHexEscapedUtf8( tag );
191 args.push_back( fromHexEscapedUtf8( tag ) );
193 emit status(
this, cmd, args );
195 d->statusBuffer = d->statusBuffer.mid( lineStart );
199 #include "gnupgprocessbase.moc"
void setUseStatusFD(bool use)
GnuPGProcessBase(QObject *parent=0)