source: psi/trunk/src/tools/openpgp/gpgproc/gpgproc.cpp

Last change on this file was 86, checked in by dmik, 19 years ago

Psi: OpenPGP: replaced printf() debug statements with qDebug() to redirect debug logs to stderr; added some minor OS/2-related corrections.

File size: 7.8 KB
Line 
1/*
2 TODO:
3 maybe have a queue for aux/command ??
4*/
5
6#include"gpgproc.h"
7
8#include<qsocketnotifier.h>
9#include<qtimer.h>
10#include"safedelete.h"
11#include"qpipe.h"
12
13#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
14#include<qprocess.h>
15#ifdef Q_WS_WIN
16#include<windows.h>
17#endif
18#else
19#include<unistd.h>
20#include"sprocess.h"
21#endif
22
23//----------------------------------------------------------------------------
24// GPGProc
25//----------------------------------------------------------------------------
26class GPGProc::Private
27{
28public:
29 Private() {}
30
31 QByteArray statusbuf;
32 SafeDelete sd;
33
34#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
35 QProcess *proc;
36#else
37 SProcess *proc;
38#endif
39 QPipe pipeAux, pipeCommand, pipeStatus;
40
41 QTimer *t;
42 QSocketNotifier *snStatus;
43};
44
45GPGProc::GPGProc()
46:QObject(0)
47{
48 d = new Private;
49 d->proc = 0;
50
51 d->snStatus = 0;
52 d->t = 0;
53}
54
55GPGProc::~GPGProc()
56{
57 closePipes();
58
59 if(d->proc) {
60 d->proc->disconnect(this);
61 if(d->proc->isRunning())
62 d->proc->kill();
63 d->sd.deleteLater(d->proc);
64 }
65
66 delete d;
67}
68
69void GPGProc::closePipes()
70{
71 d->pipeAux.close();
72 d->pipeCommand.close();
73 d->pipeStatus.close();
74
75 delete d->snStatus;
76 d->snStatus = 0;
77 delete d->t;
78 d->t = 0;
79}
80
81bool GPGProc::isRunning() const
82{
83 return d->proc->isRunning();
84}
85
86bool GPGProc::normalExit() const
87{
88 return d->proc->normalExit();
89}
90
91int GPGProc::exitStatus() const
92{
93 return d->proc->exitStatus();
94}
95
96bool GPGProc::start(const QString &bin, const QStringList &args, bool useExtra)
97{
98 if(d->proc) {
99 closePipes();
100 d->proc->disconnect(this);
101 d->sd.deleteLater(d->proc);
102 d->proc = 0;
103 }
104 d->statusbuf.resize(0);
105
106 if(!d->pipeAux.open()) {
107#ifdef GPG_DEBUG
108 qDebug("### Error creating pipeAux");
109#endif
110 closePipes();
111 return false;
112 }
113 if(!d->pipeCommand.open()) {
114#ifdef GPG_DEBUG
115 qDebug("### Error creating pipeCommand");
116#endif
117 closePipes();
118 return false;
119 }
120 if(!d->pipeStatus.open()) {
121#ifdef GPG_DEBUG
122 qDebug("### Error creating pipeStatus");
123#endif
124 closePipes();
125 return false;
126 }
127
128
129#ifdef Q_WS_WIN
130 if(!d->pipeAux.writeEnd().winDupHandle()) {
131#ifdef GPG_DEBUG
132 qDebug("### Error dup'ing pipeAux");
133#endif
134 closePipes();
135 return false;
136 }
137 if(!d->pipeCommand.writeEnd().winDupHandle()) {
138#ifdef GPG_DEBUG
139 qDebug("### Error dup'ing pipeCommand");
140#endif
141 closePipes();
142 return false;
143 }
144 if(!d->pipeStatus.readEnd().winDupHandle()) {
145#ifdef GPG_DEBUG
146 qDebug("### Error dup'ing pipeStatus");
147#endif
148 closePipes();
149 return false;
150 }
151
152 // timer
153 d->t = new QTimer;
154 connect(d->t, SIGNAL(timeout()), SLOT(timeout()));
155 d->t->start(100);
156#else
157 // status socket notifier
158 d->pipeStatus.readEnd().setBlock(false);
159 d->snStatus = new QSocketNotifier(d->pipeStatus.readEnd().id(), QSocketNotifier::Read);
160 connect(d->snStatus, SIGNAL(activated(int)), SLOT(sn_activated(int)));
161#endif
162
163 /*{
164 // test: write some data into the pipe
165 QCString cs = "Foobar";
166 d->pipeStatus.write(cs);
167 QByteArray buf = d->pipeStatus.readAll();
168 QCString cs2 = buf.data();
169 if(cs != cs2)
170 qDebug("### Pipe test failed.");
171 else
172 qDebug("### Pipe test succeeded.");
173 }*/
174
175#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
176 d->proc = new QProcess;
177#else
178 d->proc = new SProcess;
179#endif
180
181#ifdef GPG_DEBUG
182 qDebug("### Pipe setup complete.");
183#endif
184
185 QStringList fullargs;
186 fullargs += bin;
187 fullargs += "--no-tty";
188
189 if(useExtra) {
190 fullargs += "--status-fd";
191 fullargs += d->pipeStatus.writeEnd().toString();
192
193 fullargs += "--command-fd";
194 fullargs += d->pipeCommand.readEnd().toString();
195 }
196
197 bool seen_special_filenames = false;
198 for(QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) {
199 const QString &a = (*it);
200 if(a == "-&?") {
201 seen_special_filenames = true;
202 fullargs += (QString("\"-&") + d->pipeAux.readEnd().toString() + "\"");
203 } else {
204 fullargs += a;
205 }
206 }
207 // insert --enable-special-filenames after --no-tty
208 if(seen_special_filenames)
209 fullargs.insert(fullargs.at(2), "--enable-special-filenames");
210
211 // show full command
212#ifdef GPG_DEBUG
213 qDebug("### GPGProc: %s", fullargs.join(" ").latin1());
214#endif
215
216 d->proc->setArguments(fullargs);
217
218#if !defined(Q_WS_WIN) && !defined(Q_OS_OS2)
219 QValueList<int> plist;
220 plist += d->pipeAux.writeEnd().id();
221 plist += d->pipeCommand.writeEnd().id();
222 plist += d->pipeStatus.readEnd().id();
223 d->proc->setClosePipeList(plist);
224#endif
225
226 connect(d->proc, SIGNAL(readyReadStdout()), SLOT(proc_readyReadStdout()));
227 connect(d->proc, SIGNAL(readyReadStderr()), SLOT(proc_readyReadStderr()));
228 connect(d->proc, SIGNAL(wroteToStdin()), SLOT(proc_wroteToStdin()));
229 connect(d->proc, SIGNAL(processExited()), SLOT(proc_processExited()));
230
231 bool ok = d->proc->start();
232
233 // we don't care about these
234 d->pipeAux.closeReadEnd();
235 d->pipeCommand.closeReadEnd();
236 d->pipeStatus.closeWriteEnd();
237
238 if(!ok) {
239 closePipes();
240 d->proc->disconnect(this);
241 d->sd.deleteLater(d->proc);
242 d->proc = 0;
243 return false;
244 }
245
246 return true;
247}
248
249void GPGProc::writeToStdin(const QByteArray &buf)
250{
251 d->proc->writeToStdin(buf);
252}
253
254void GPGProc::writeToAux(const QByteArray &buf)
255{
256 d->pipeAux.write(buf);
257 wroteToAux();
258}
259
260void GPGProc::writeToCommand(const QByteArray &buf)
261{
262 d->pipeCommand.write(buf);
263 wroteToCommand();
264}
265
266void GPGProc::closeStdin()
267{
268 d->proc->closeStdin();
269}
270
271void GPGProc::closeAux()
272{
273 d->pipeAux.close();
274}
275
276void GPGProc::closeCommand()
277{
278 d->pipeCommand.close();
279}
280
281QByteArray GPGProc::readStdout()
282{
283 return d->proc->readStdout();
284}
285
286QByteArray GPGProc::readStderr()
287{
288 return d->proc->readStderr();
289}
290
291void GPGProc::proc_readyReadStdout()
292{
293 SafeDeleteLock s(&d->sd);
294 readyReadStdout();
295}
296
297void GPGProc::proc_readyReadStderr()
298{
299 SafeDeleteLock s(&d->sd);
300 readyReadStderr();
301}
302
303void GPGProc::proc_wroteToStdin()
304{
305 SafeDeleteLock s(&d->sd);
306 wroteToStdin();
307}
308
309void GPGProc::proc_processExited()
310{
311 SafeDeleteLock s(&d->sd);
312
313#ifdef Q_WS_WIN
314 timeout();
315 delete d->t;
316 d->t = 0;
317#else
318 // maybe there is some status left??
319 QByteArray buf = d->pipeStatus.readAll();
320 if(!buf.isEmpty())
321 processStatusData(buf);
322#endif
323 processExited();
324
325#if defined(Q_OS_OS2)
326 closePipes();
327#endif
328}
329
330#ifdef Q_WS_WIN
331void GPGProc::timeout()
332{
333 QByteArray buf = d->pipeStatus.readAll();
334 if(!buf.isEmpty())
335 processStatusData(buf);
336}
337
338void GPGProc::sn_activated(int)
339{
340}
341#else
342void GPGProc::timeout()
343{
344}
345
346void GPGProc::sn_activated(int)
347{
348 bool done;
349 QByteArray buf = d->pipeStatus.readAll(&done);
350 if(done) {
351 d->pipeStatus.close();
352 delete d->snStatus;
353 d->snStatus = 0;
354 }
355 if(!buf.isEmpty())
356 processStatusData(buf);
357}
358#endif
359
360void GPGProc::processStatusData(const QByteArray &buf)
361{
362 // append to the statusbuf
363 int oldsize = d->statusbuf.size();
364 d->statusbuf.resize(oldsize + buf.size());
365 memcpy(d->statusbuf.data() + oldsize, buf.data(), buf.size());
366
367 // extract all lines
368 QStringList list;
369 while(1) {
370 int n = 0;
371 int len = d->statusbuf.size();
372 char *p = (char *)d->statusbuf.data();
373 for(; n < len; ++n) {
374 if(p[n] == '\n')
375 break;
376 }
377 // no full line
378 if(n >= len)
379 break;
380 // extract the string from statusbuf
381 ++n;
382 QCString cs;
383 cs.resize(n+1);
384 memcpy(cs.data(), p, n);
385 int newsize = len - n;
386 memmove(p, p + n, newsize);
387 d->statusbuf.resize(newsize);
388
389 // convert to string without newline
390 QString str = QString::fromUtf8(cs);
391 str.truncate(str.length()-1);
392 // ensure it has a proper header
393 if(str.left(9) != "[GNUPG:] ")
394 continue;
395 // take it off
396 str = str.mid(9);
397 // add to the list
398 list += str;
399 }
400
401 for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
402 statusLine(*it);
403}
Note: See TracBrowser for help on using the repository browser.